From 7d253d81ed5d087b12df2f29ae2ea6ef4e98e151 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 15:31:15 +0000 Subject: [PATCH 01/19] migrate to third party shapes library --- NuGet.config | 1 + src/ImageSharp.Drawing/Draw.cs | 3 +- src/ImageSharp.Drawing/DrawRectangle.cs | 6 +- src/ImageSharp.Drawing/Fill.cs | 4 +- src/ImageSharp.Drawing/FillRectangle.cs | 5 +- .../Paths/BezierLineSegment.cs | 119 - src/ImageSharp.Drawing/Paths/ILineSegment.cs | 21 - src/ImageSharp.Drawing/Paths/IPath.cs | 48 - src/ImageSharp.Drawing/Paths/InternalPath.cs | 516 --- .../Paths/LinearLineSegment.cs | 55 - src/ImageSharp.Drawing/Paths/Path.cs | 51 - src/ImageSharp.Drawing/Pens/Pen{TColor}.cs | 1 - .../Pens/Processors/PenApplicator.cs | 1 - .../{Paths => Pens/Processors}/PointInfo.cs | 18 +- .../Processors/DrawPathProcessor.cs | 30 +- .../Processors/FillShapeProcessor.cs | 4 +- .../Processors/PointInfoExtensions.cs | 37 + .../Processors/RectangleExtensions.cs | 32 + .../Shapes/BezierPolygon.cs | 93 - .../Shapes/ComplexPolygon.cs | 246 -- src/ImageSharp.Drawing/Shapes/IShape.cs | 56 - .../Shapes/LinearPolygon.cs | 93 - src/ImageSharp.Drawing/Shapes/Polygon.cs | 156 - .../Shapes/PolygonClipper/Clipper.cs | 3860 ----------------- .../Shapes/PolygonClipper/ClipperException.cs | 31 - .../Shapes/PolygonClipper/Direction.cs | 31 - .../Shapes/PolygonClipper/EdgeSide.cs | 31 - .../Shapes/PolygonClipper/IntersectNode.cs | 38 - .../PolygonClipper/IntersectNodeSort.cs | 48 - .../Shapes/PolygonClipper/Join.cs | 38 - .../Shapes/PolygonClipper/LocalMinima.cs | 44 - .../Shapes/PolygonClipper/Maxima.cs | 38 - .../Shapes/PolygonClipper/OutPt.cs | 43 - .../Shapes/PolygonClipper/OutRec.cs | 64 - .../Shapes/PolygonClipper/PolyNode.cs | 179 - .../Shapes/PolygonClipper/PolyTree.cs | 81 - .../Shapes/PolygonClipper/PolyType.cs | 31 - .../Shapes/PolygonClipper/README.md | 40 - .../Shapes/PolygonClipper/Scanbeam.cs | 33 - .../Shapes/PolygonClipper/TEdge.cs | 118 - .../Shapes/RectangularPolygon.cs | 281 -- src/ImageSharp.Drawing/project.json | 1 + .../Drawing/FillRectangle.cs | 10 +- 43 files changed, 108 insertions(+), 6528 deletions(-) delete mode 100644 src/ImageSharp.Drawing/Paths/BezierLineSegment.cs delete mode 100644 src/ImageSharp.Drawing/Paths/ILineSegment.cs delete mode 100644 src/ImageSharp.Drawing/Paths/IPath.cs delete mode 100644 src/ImageSharp.Drawing/Paths/InternalPath.cs delete mode 100644 src/ImageSharp.Drawing/Paths/LinearLineSegment.cs delete mode 100644 src/ImageSharp.Drawing/Paths/Path.cs rename src/ImageSharp.Drawing/{Paths => Pens/Processors}/PointInfo.cs (54%) create mode 100644 src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs create mode 100644 src/ImageSharp.Drawing/Processors/RectangleExtensions.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/BezierPolygon.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/IShape.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/LinearPolygon.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/Polygon.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs delete mode 100644 src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs diff --git a/NuGet.config b/NuGet.config index b2c967cc97..88d71e7bac 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@  + diff --git a/src/ImageSharp.Drawing/Draw.cs b/src/ImageSharp.Drawing/Draw.cs index c10665b832..8c3dbb1b5a 100644 --- a/src/ImageSharp.Drawing/Draw.cs +++ b/src/ImageSharp.Drawing/Draw.cs @@ -9,10 +9,9 @@ namespace ImageSharp using System.Numerics; using Drawing; using Drawing.Brushes; - using Drawing.Paths; using Drawing.Pens; using Drawing.Processors; - using Drawing.Shapes; + using SixLabors.Shapes; /// /// Extension methods for the type. diff --git a/src/ImageSharp.Drawing/DrawRectangle.cs b/src/ImageSharp.Drawing/DrawRectangle.cs index 38ed578b65..17d6d5f368 100644 --- a/src/ImageSharp.Drawing/DrawRectangle.cs +++ b/src/ImageSharp.Drawing/DrawRectangle.cs @@ -9,10 +9,10 @@ namespace ImageSharp using Drawing; using Drawing.Brushes; - using Drawing.Paths; using Drawing.Pens; using Drawing.Processors; - using Drawing.Shapes; + + using SixLabors.Shapes; /// /// Extension methods for the type. @@ -33,7 +33,7 @@ namespace ImageSharp public static Image DrawPolygon(this Image source, IPen pen, RectangleF shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, (IPath)new RectangularPolygon(shape), options)); + return source.Apply(new DrawPathProcessor(pen, (IPath)new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options)); } /// diff --git a/src/ImageSharp.Drawing/Fill.cs b/src/ImageSharp.Drawing/Fill.cs index c0f43bdd18..637950e76d 100644 --- a/src/ImageSharp.Drawing/Fill.cs +++ b/src/ImageSharp.Drawing/Fill.cs @@ -9,9 +9,9 @@ namespace ImageSharp using System.Numerics; using Drawing; using Drawing.Brushes; - using Drawing.Paths; using Drawing.Processors; - using Drawing.Shapes; + + using SixLabors.Shapes; /// /// Extension methods for the type. diff --git a/src/ImageSharp.Drawing/FillRectangle.cs b/src/ImageSharp.Drawing/FillRectangle.cs index d29b58e1b8..7749e7c921 100644 --- a/src/ImageSharp.Drawing/FillRectangle.cs +++ b/src/ImageSharp.Drawing/FillRectangle.cs @@ -10,7 +10,6 @@ namespace ImageSharp using Drawing; using Drawing.Brushes; using Drawing.Processors; - using Drawing.Shapes; /// /// Extension methods for the type. @@ -31,7 +30,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, RectangleF shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, new RectangularPolygon(shape), options)); + return source.Apply(new FillShapeProcessor(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options)); } /// @@ -45,7 +44,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, RectangleF shape) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, new RectangularPolygon(shape), GraphicsOptions.Default)); + return source.Apply(new FillShapeProcessor(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), GraphicsOptions.Default)); } /// diff --git a/src/ImageSharp.Drawing/Paths/BezierLineSegment.cs b/src/ImageSharp.Drawing/Paths/BezierLineSegment.cs deleted file mode 100644 index 647f97f1e9..0000000000 --- a/src/ImageSharp.Drawing/Paths/BezierLineSegment.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Paths -{ - using System.Numerics; - - /// - /// Represents a line segment that conistst of control points that will be rendered as a cubic bezier curve - /// - /// - public class BezierLineSegment : ILineSegment - { - /// - /// The segments per curve. - /// code for this taken from - /// - private const int SegmentsPerCurve = 50; - - /// - /// The line points. - /// - private readonly Vector2[] linePoints; - - /// - /// Initializes a new instance of the class. - /// - /// The points. - public BezierLineSegment(params Vector2[] points) - { - Guard.NotNull(points, nameof(points)); - Guard.MustBeGreaterThanOrEqualTo(points.Length, 4, nameof(points)); - - this.linePoints = this.GetDrawingPoints(points); - } - - /// - /// Returns the current a simple linear path. - /// - /// - /// Returns the current as simple linear path. - /// - public Vector2[] AsSimpleLinearPath() - { - return this.linePoints; - } - - /// - /// Returns the drawing points along the line. - /// - /// The control points. - /// - /// The . - /// - private Vector2[] GetDrawingPoints(Vector2[] controlPoints) - { - // TODO we need to calculate an optimal SegmentsPerCurve value - // depending on the calcualted length of this curve - int curveCount = (controlPoints.Length - 1) / 3; - int finalPointCount = (SegmentsPerCurve * curveCount) + 1; // we have SegmentsPerCurve for each curve plus the origon point; - - Vector2[] drawingPoints = new Vector2[finalPointCount]; - - int position = 0; - int targetPoint = controlPoints.Length - 3; - for (int i = 0; i < targetPoint; i += 3) - { - Vector2 p0 = controlPoints[i]; - Vector2 p1 = controlPoints[i + 1]; - Vector2 p2 = controlPoints[i + 2]; - Vector2 p3 = controlPoints[i + 3]; - - // only do this for the first end point. When i != 0, this coincides with the end point of the previous segment, - if (i == 0) - { - drawingPoints[position++] = this.CalculateBezierPoint(0, p0, p1, p2, p3); - } - - for (int j = 1; j <= SegmentsPerCurve; j++) - { - float t = j / (float)SegmentsPerCurve; - drawingPoints[position++] = this.CalculateBezierPoint(t, p0, p1, p2, p3); - } - } - - return drawingPoints; - } - - /// - /// Calculates the bezier point along the line. - /// - /// The position within the line. - /// The p 0. - /// The p 1. - /// The p 2. - /// The p 3. - /// - /// The . - /// - private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) - { - float u = 1 - t; - float tt = t * t; - float uu = u * u; - float uuu = uu * u; - float ttt = tt * t; - - Vector2 p = uuu * p0; // first term - - p += 3 * uu * t * p1; // second term - p += 3 * u * tt * p2; // third term - p += ttt * p3; // fourth term - - return p; - } - } -} diff --git a/src/ImageSharp.Drawing/Paths/ILineSegment.cs b/src/ImageSharp.Drawing/Paths/ILineSegment.cs deleted file mode 100644 index 380f0bf40c..0000000000 --- a/src/ImageSharp.Drawing/Paths/ILineSegment.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Paths -{ - using System.Numerics; - - /// - /// Represents a simple path segment - /// - public interface ILineSegment - { - /// - /// Converts the into a simple linear path.. - /// - /// Returns the current as simple linear path. - Vector2[] AsSimpleLinearPath(); // TODO move this over to ReadonlySpan once available - } -} diff --git a/src/ImageSharp.Drawing/Paths/IPath.cs b/src/ImageSharp.Drawing/Paths/IPath.cs deleted file mode 100644 index 278d972511..0000000000 --- a/src/ImageSharp.Drawing/Paths/IPath.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Paths -{ - using System.Numerics; - - /// - /// Represents a logic path that can be drawn - /// - public interface IPath : ILineSegment - { - /// - /// Gets the bounds enclosing the path - /// - /// - /// The bounds. - /// - RectangleF Bounds { get; } - - /// - /// Gets a value indicating whether this instance is closed. - /// - /// - /// true if this instance is closed; otherwise, false. - /// - bool IsClosed { get; } - - /// - /// Gets the length of the path - /// - /// - /// The length. - /// - float Length { get; } - - /// - /// Calculates the distance along and away from the path for a specified point. - /// - /// The point along the path. - /// - /// Returns details about the point and its distance away from the path. - /// - PointInfo Distance(Vector2 point); - } -} diff --git a/src/ImageSharp.Drawing/Paths/InternalPath.cs b/src/ImageSharp.Drawing/Paths/InternalPath.cs deleted file mode 100644 index 36a0704cbe..0000000000 --- a/src/ImageSharp.Drawing/Paths/InternalPath.cs +++ /dev/null @@ -1,516 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// -namespace ImageSharp.Drawing.Paths -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - - /// - /// Internal logic for integrating linear paths. - /// - internal class InternalPath - { - /// - /// The maximum vector - /// - private static readonly Vector2 MaxVector = new Vector2(float.MaxValue); - - /// - /// The locker. - /// - private static readonly object Locker = new object(); - - /// - /// The points. - /// - private readonly Vector2[] points; - - /// - /// The closed path. - /// - private readonly bool closedPath; - - /// - /// The total distance. - /// - private readonly Lazy totalDistance; - - /// - /// The constant. - /// - private float[] constant; - - /// - /// The multiples. - /// - private float[] multiple; - - /// - /// The distances. - /// - private float[] distance; - - /// - /// The calculated. - /// - private bool calculated = false; - - /// - /// Initializes a new instance of the class. - /// - /// The segments. - /// if set to true [is closed path]. - internal InternalPath(ILineSegment[] segments, bool isClosedPath) - : this(Simplify(segments), isClosedPath) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The segment. - /// if set to true [is closed path]. - internal InternalPath(ILineSegment segment, bool isClosedPath) - : this(segment.AsSimpleLinearPath(), isClosedPath) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The points. - /// if set to true [is closed path]. - internal InternalPath(Vector2[] points, bool isClosedPath) - { - this.points = points; - this.closedPath = isClosedPath; - - float minX = this.points.Min(x => x.X); - float maxX = this.points.Max(x => x.X); - float minY = this.points.Min(x => x.Y); - float maxY = this.points.Max(x => x.Y); - - this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY); - this.totalDistance = new Lazy(this.CalculateLength); - } - - /// - /// Gets the bounds. - /// - /// - /// The bounds. - /// - public RectangleF Bounds - { - get; - } - - /// - /// Gets the length. - /// - /// - /// The length. - /// - public float Length => this.totalDistance.Value; - - /// - /// Gets the points. - /// - /// - /// The points. - /// - internal Vector2[] Points => this.points; - - /// - /// Calculates the distance from the path. - /// - /// The point. - /// Returns the distance from the path - public PointInfo DistanceFromPath(Vector2 point) - { - this.CalculateConstants(); - - PointInfoInternal internalInfo = default(PointInfoInternal); - internalInfo.DistanceSquared = float.MaxValue; // Set it to max so that CalculateShorterDistance can reduce it back down - - int polyCorners = this.points.Length; - - if (!this.closedPath) - { - polyCorners -= 1; - } - - int closestPoint = 0; - for (int i = 0; i < polyCorners; i++) - { - int next = i + 1; - if (this.closedPath && next == polyCorners) - { - next = 0; - } - - if (this.CalculateShorterDistance(this.points[i], this.points[next], point, ref internalInfo)) - { - closestPoint = i; - } - } - - return new PointInfo - { - DistanceAlongPath = this.distance[closestPoint] + Vector2.Distance(this.points[closestPoint], point), - DistanceFromPath = (float)Math.Sqrt(internalInfo.DistanceSquared), - SearchPoint = point, - ClosestPointOnPath = internalInfo.PointOnLine - }; - } - - /// - /// Based on a line described by and - /// populate a buffer for all points on the path that the line intersects. - /// - /// The start. - /// The end. - /// The buffer. - /// The count. - /// The offset. - /// number iof intersections hit - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - int polyCorners = this.points.Length; - - if (!this.closedPath) - { - polyCorners -= 1; - } - - int position = 0; - for (int i = 0; i < polyCorners && count > 0; i++) - { - int next = i + 1; - if (this.closedPath && next == polyCorners) - { - next = 0; - } - - Vector2 point = FindIntersection(this.points[i], this.points[next], start, end); - if (point != MaxVector) - { - buffer[position + offset] = point; - position++; - count--; - } - } - - return position; - } - - /// - /// Determines if the specified point is inside or outside the path. - /// - /// The point. - /// Returns true if the point is inside the closed path. - public bool PointInPolygon(Vector2 point) - { - // You can only be inside a path if its "closed" - if (!this.closedPath) - { - return false; - } - - if (!this.Bounds.Contains(point.X, point.Y)) - { - return false; - } - - this.CalculateConstants(); - - Vector2[] poly = this.points; - int polyCorners = poly.Length; - - int j = polyCorners - 1; - bool oddNodes = false; - - for (int i = 0; i < polyCorners; i++) - { - if ((poly[i].Y < point.Y && poly[j].Y >= point.Y) - || (poly[j].Y < point.Y && poly[i].Y >= point.Y)) - { - oddNodes ^= (point.Y * this.multiple[i]) + this.constant[i] < point.X; - } - - j = i; - } - - return oddNodes; - } - - /// - /// Determins if the bounding box for 2 lines - /// described by and - /// and and overlap. - /// - /// The line1 start. - /// The line1 end. - /// The line2 start. - /// The line2 end. - /// Returns true it the bounding box of the 2 lines intersect - private static bool BoundingBoxesIntersect(Vector2 line1Start, Vector2 line1End, Vector2 line2Start, Vector2 line2End) - { - Vector2 topLeft1 = Vector2.Min(line1Start, line1End); - Vector2 bottomRight1 = Vector2.Max(line1Start, line1End); - - Vector2 topLeft2 = Vector2.Min(line2Start, line2End); - Vector2 bottomRight2 = Vector2.Max(line2Start, line2End); - - float left1 = topLeft1.X; - float right1 = bottomRight1.X; - float top1 = topLeft1.Y; - float bottom1 = bottomRight1.Y; - - float left2 = topLeft2.X; - float right2 = bottomRight2.X; - float top2 = topLeft2.Y; - float bottom2 = bottomRight2.Y; - - return left1 <= right2 && right1 >= left2 - && - top1 <= bottom2 && bottom1 >= top2; - } - - /// - /// Finds the point on line described by and - /// that intersects with line described by and - /// - /// The line1 start. - /// The line1 end. - /// The line2 start. - /// The line2 end. - /// - /// A describing the point that the 2 lines cross or if they do not. - /// - private static Vector2 FindIntersection(Vector2 line1Start, Vector2 line1End, Vector2 line2Start, Vector2 line2End) - { - // do bounding boxes overlap, if not then the lines can't and return fast. - if (!BoundingBoxesIntersect(line1Start, line1End, line2Start, line2End)) - { - return MaxVector; - } - - Vector2 line1Diff = line1End - line1Start; - Vector2 line2Diff = line2End - line2Start; - - Vector2 point; - if (line1Diff.X == 0) - { - float slope = line2Diff.Y / line2Diff.X; - float yinter = line2Start.Y - (slope * line2Start.X); - float y = (line1Start.X * slope) + yinter; - point = new Vector2(line1Start.X, y); - - // horizontal and vertical lines - } - else if (line2Diff.X == 0) - { - float slope = line1Diff.Y / line1Diff.X; - float yinter = line1Start.Y - (slope * line1Start.X); - float y = (line2Start.X * slope) + yinter; - point = new Vector2(line2Start.X, y); - - // horizontal and vertical lines - } - else - { - float slope1 = line1Diff.Y / line1Diff.X; - float slope2 = line2Diff.Y / line2Diff.X; - - float yinter1 = line1Start.Y - (slope1 * line1Start.X); - float yinter2 = line2Start.Y - (slope2 * line2Start.X); - - if (slope1 == slope2 && yinter1 != yinter2) - { - return MaxVector; - } - - float x = (yinter2 - yinter1) / (slope1 - slope2); - float y = (slope1 * x) + yinter1; - - point = new Vector2(x, y); - } - - if (BoundingBoxesIntersect(line1Start, line1End, point, point)) - { - return point; - } - else if (BoundingBoxesIntersect(line2Start, line2End, point, point)) - { - return point; - } - - return MaxVector; - } - - /// - /// Simplifies the collection of segments. - /// - /// The segments. - /// - /// The . - /// - private static Vector2[] Simplify(ILineSegment[] segments) - { - List simplified = new List(); - foreach (ILineSegment seg in segments) - { - simplified.AddRange(seg.AsSimpleLinearPath()); - } - - return simplified.ToArray(); - } - - /// - /// Returns the length of the path. - /// - /// - /// The . - /// - private float CalculateLength() - { - float length = 0; - int polyCorners = this.points.Length; - - if (!this.closedPath) - { - polyCorners -= 1; - } - - for (int i = 0; i < polyCorners; i++) - { - int next = i + 1; - if (this.closedPath && next == polyCorners) - { - next = 0; - } - - length += Vector2.Distance(this.points[i], this.points[next]); - } - - return length; - } - - /// - /// Calculate the constants. - /// - private void CalculateConstants() - { - // http://alienryderflex.com/polygon/ source for point in polygon logic - if (this.calculated) - { - return; - } - - lock (Locker) - { - if (this.calculated) - { - return; - } - - Vector2[] poly = this.points; - int polyCorners = poly.Length; - this.constant = new float[polyCorners]; - this.multiple = new float[polyCorners]; - this.distance = new float[polyCorners]; - int i, j = polyCorners - 1; - - this.distance[0] = 0; - - for (i = 0; i < polyCorners; i++) - { - this.distance[j] = this.distance[i] + Vector2.Distance(poly[i], poly[j]); - if (poly[j].Y == poly[i].Y) - { - this.constant[i] = poly[i].X; - this.multiple[i] = 0; - } - else - { - Vector2 subtracted = poly[j] - poly[i]; - this.constant[i] = (poly[i].X - ((poly[i].Y * poly[j].X) / subtracted.Y)) + ((poly[i].Y * poly[i].X) / subtracted.Y); - this.multiple[i] = subtracted.X / subtracted.Y; - } - - j = i; - } - - this.calculated = true; - } - } - - /// - /// Calculate any shorter distances along the path. - /// - /// The start position. - /// The end position. - /// The current point. - /// The info. - /// - /// The . - /// - private bool CalculateShorterDistance(Vector2 start, Vector2 end, Vector2 point, ref PointInfoInternal info) - { - Vector2 diffEnds = end - start; - - float lengthSquared = diffEnds.LengthSquared(); - Vector2 diff = point - start; - - Vector2 multiplied = diff * diffEnds; - float u = (multiplied.X + multiplied.Y) / lengthSquared; - - if (u > 1) - { - u = 1; - } - else if (u < 0) - { - u = 0; - } - - Vector2 multipliedByU = diffEnds * u; - - Vector2 pointOnLine = start + multipliedByU; - - Vector2 d = pointOnLine - point; - - float dist = d.LengthSquared(); - - if (info.DistanceSquared > dist) - { - info.DistanceSquared = dist; - info.PointOnLine = pointOnLine; - return true; - } - - return false; - } - - /// - /// Contains information about the current point. - /// - private struct PointInfoInternal - { - /// - /// The distance squared. - /// - public float DistanceSquared; - - /// - /// The point on the current line. - /// - public Vector2 PointOnLine; - } - } -} diff --git a/src/ImageSharp.Drawing/Paths/LinearLineSegment.cs b/src/ImageSharp.Drawing/Paths/LinearLineSegment.cs deleted file mode 100644 index 6942ce5a5a..0000000000 --- a/src/ImageSharp.Drawing/Paths/LinearLineSegment.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Paths -{ - using System.Linq; - using System.Numerics; - - /// - /// Represents a series of control points that will be joined by straight lines - /// - /// - public class LinearLineSegment : ILineSegment - { - /// - /// The collection of points. - /// - private readonly Vector2[] points; - - /// - /// Initializes a new instance of the class. - /// - /// The start. - /// The end. - public LinearLineSegment(Vector2 start, Vector2 end) - : this(new[] { start, end }) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The points. - public LinearLineSegment(params Vector2[] points) - { - Guard.NotNull(points, nameof(points)); - Guard.MustBeGreaterThanOrEqualTo(points.Count(), 2, nameof(points)); - - this.points = points; - } - - /// - /// Converts the into a simple linear path.. - /// - /// - /// Returns the current as simple linear path. - /// - public Vector2[] AsSimpleLinearPath() - { - return this.points; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Paths/Path.cs b/src/ImageSharp.Drawing/Paths/Path.cs deleted file mode 100644 index eb2ab5e854..0000000000 --- a/src/ImageSharp.Drawing/Paths/Path.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Paths -{ - using System.Numerics; - - /// - /// A aggregate of s making a single logical path - /// - /// - public class Path : IPath - { - /// - /// The inner path. - /// - private readonly InternalPath innerPath; - - /// - /// Initializes a new instance of the class. - /// - /// The segment. - public Path(params ILineSegment[] segment) - { - this.innerPath = new InternalPath(segment, false); - } - - /// - public RectangleF Bounds => this.innerPath.Bounds; - - /// - public bool IsClosed => false; - - /// - public float Length => this.innerPath.Length; - - /// - public Vector2[] AsSimpleLinearPath() - { - return this.innerPath.Points; - } - - /// - public PointInfo Distance(Vector2 point) - { - return this.innerPath.DistanceFromPath(point); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs index a08c7a7faf..bbb3c25597 100644 --- a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs +++ b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs @@ -9,7 +9,6 @@ namespace ImageSharp.Drawing.Pens using System.Numerics; using ImageSharp.Drawing.Brushes; - using ImageSharp.Drawing.Paths; using Processors; /// diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs index e07b969495..222598d85f 100644 --- a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs +++ b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs @@ -6,7 +6,6 @@ namespace ImageSharp.Drawing.Processors { using System; - using Paths; /// /// primitive that converts a into a color and a distance away from the drawable part of the path. diff --git a/src/ImageSharp.Drawing/Paths/PointInfo.cs b/src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs similarity index 54% rename from src/ImageSharp.Drawing/Paths/PointInfo.cs rename to src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs index a2cbf1e73c..6fc78b09b6 100644 --- a/src/ImageSharp.Drawing/Paths/PointInfo.cs +++ b/src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs @@ -3,33 +3,29 @@ // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp.Drawing.Paths +namespace ImageSharp.Drawing.Processors { + using System; using System.Numerics; /// - /// Returns meta data about the nearest point on a path from a vector + /// Returns details about how far away from the inside of a shape and the color the pixel could be. /// public struct PointInfo { /// - /// The search point - /// - public Vector2 SearchPoint; - - /// - /// The distance along path is away from the start of the path + /// The distance along path /// public float DistanceAlongPath; /// - /// The distance is away from . + /// The distance from path /// public float DistanceFromPath; /// - /// The closest point to that lies on the path. + /// The search point /// - public Vector2 ClosestPointOnPath; + public Vector2 SearchPoint; } } diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index f7bdcb6895..d6b2f3eb28 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -6,13 +6,13 @@ namespace ImageSharp.Drawing.Processors { using System; + using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Threading.Tasks; using ImageSharp.Processing; - using Paths; using Pens; - using Shapes; + using SixLabors.Shapes; using Rectangle = ImageSharp.Rectangle; /// @@ -38,7 +38,7 @@ namespace ImageSharp.Drawing.Processors /// The shape. /// The options. public DrawPathProcessor(IPen pen, IShape shape, GraphicsOptions options) - : this(pen, shape.ToArray(), options) + : this(pen, shape.Paths, options) { } @@ -59,24 +59,24 @@ namespace ImageSharp.Drawing.Processors /// The pen. /// The paths. /// The options. - public DrawPathProcessor(IPen pen, IPath[] paths, GraphicsOptions options) + public DrawPathProcessor(IPen pen, IEnumerable paths, GraphicsOptions options) { - this.paths = paths; + this.paths = paths.ToArray(); this.pen = pen; this.options = options; - if (paths.Length != 1) + if (this.paths.Length != 1) { - var maxX = paths.Max(x => x.Bounds.Right); - var minX = paths.Min(x => x.Bounds.Left); - var maxY = paths.Max(x => x.Bounds.Bottom); - var minY = paths.Min(x => x.Bounds.Top); + var maxX = this.paths.Max(x => x.Bounds.Right); + var minX = this.paths.Min(x => x.Bounds.Left); + var maxY = this.paths.Max(x => x.Bounds.Bottom); + var minY = this.paths.Min(x => x.Bounds.Top); this.region = new RectangleF(minX, minY, maxX - minX, maxY - minY); } else { - this.region = paths[0].Bounds; + this.region = this.paths[0].Bounds.Convert(); } } @@ -119,7 +119,7 @@ namespace ImageSharp.Drawing.Processors minY, maxY, this.ParallelOptions, - y => + (int y) => { int offsetY = y - polyStartY; var currentPoint = default(Vector2); @@ -131,7 +131,7 @@ namespace ImageSharp.Drawing.Processors var dist = this.Closest(currentPoint); - var color = applicator.GetColor(dist); + var color = applicator.GetColor(dist.Convert()); var opacity = this.Opacity(color.DistanceFromElement); @@ -154,9 +154,9 @@ namespace ImageSharp.Drawing.Processors } } - private PointInfo Closest(Vector2 point) + private SixLabors.Shapes.PointInfo Closest(Vector2 point) { - PointInfo result = default(PointInfo); + SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); float distance = float.MaxValue; for (int i = 0; i < this.paths.Length; i++) diff --git a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs b/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs index 4696b86132..14e99cba37 100644 --- a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Drawing.Processors using System.Threading.Tasks; using Drawing; using ImageSharp.Processing; - using Shapes; + using SixLabors.Shapes; using Rectangle = ImageSharp.Rectangle; /// @@ -44,7 +44,7 @@ namespace ImageSharp.Drawing.Processors /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - Rectangle rect = RectangleF.Ceiling(this.poly.Bounds); // rounds the points out away from the center + Rectangle rect = RectangleF.Ceiling(this.poly.Bounds.Convert()); // rounds the points out away from the center int polyStartY = rect.Y - DrawPadding; int polyEndY = rect.Bottom + DrawPadding; diff --git a/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs b/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs new file mode 100644 index 0000000000..939a718450 --- /dev/null +++ b/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing.Processors +{ + using System; + using System.Buffers; + using System.Numerics; + using System.Threading.Tasks; + using Drawing; + using ImageSharp.Processing; + using SixLabors.Shapes; + using Rectangle = ImageSharp.Rectangle; + + /// + /// Extension methods for helping to bridge Shaper2D and ImageSharp primitives. + /// + internal static class PointInfoExtensions + { + /// + /// Converts a to an ImageSharp . + /// + /// The source. + /// A representation of this + public static PointInfo Convert(this SixLabors.Shapes.PointInfo source) + { + return new PointInfo + { + DistanceAlongPath = source.DistanceAlongPath, + DistanceFromPath = source.DistanceFromPath, + SearchPoint = source.SearchPoint + }; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processors/RectangleExtensions.cs b/src/ImageSharp.Drawing/Processors/RectangleExtensions.cs new file mode 100644 index 0000000000..327b618fa4 --- /dev/null +++ b/src/ImageSharp.Drawing/Processors/RectangleExtensions.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing.Processors +{ + using System; + using System.Buffers; + using System.Numerics; + using System.Threading.Tasks; + using Drawing; + using ImageSharp.Processing; + using SixLabors.Shapes; + using Rectangle = ImageSharp.Rectangle; + + /// + /// Extension methods for helping to bridge Shaper2D and ImageSharp primitives. + /// + internal static class RectangleExtensions + { + /// + /// Converts a Shaper2D to an ImageSharp . + /// + /// The source. + /// A representation of this + public static RectangleF Convert(this SixLabors.Shapes.Rectangle source) + { + return new RectangleF(source.Location.X, source.Location.Y, source.Size.Width, source.Size.Height); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/BezierPolygon.cs b/src/ImageSharp.Drawing/Shapes/BezierPolygon.cs deleted file mode 100644 index b69ded2075..0000000000 --- a/src/ImageSharp.Drawing/Shapes/BezierPolygon.cs +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System.Collections; - using System.Collections.Generic; - using System.Numerics; - using Paths; - - /// - /// Represents a polygon made up exclusivly of a single close cubic Bezier curve. - /// - public sealed class BezierPolygon : IShape - { - private Polygon innerPolygon; - - /// - /// Initializes a new instance of the class. - /// - /// The points. - public BezierPolygon(params Vector2[] points) - { - this.innerPolygon = new Polygon(new BezierLineSegment(points)); - } - - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - public RectangleF Bounds => this.innerPolygon.Bounds; - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - public int MaxIntersections => this.innerPolygon.MaxIntersections; - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// The distance from the shape. - /// - public float Distance(Vector2 point) => this.innerPolygon.Distance(point); - - /// - /// Based on a line described by and - /// populate a buffer for all points on the polygon that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - return this.innerPolygon.FindIntersections(start, end, buffer, count, offset); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return this.innerPolygon.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.innerPolygon.GetEnumerator(); - } - } -} diff --git a/src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs b/src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs deleted file mode 100644 index fd709719c1..0000000000 --- a/src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - - using Paths; - using PolygonClipper; - - /// - /// Represents a complex polygon made up of one or more outline - /// polygons and one or more holes to punch out of them. - /// - /// - public sealed class ComplexPolygon : IShape - { - private const float ClipperScaleFactor = 100f; - private IShape[] shapes; - private IEnumerable paths; - - /// - /// Initializes a new instance of the class. - /// - /// The outline. - /// The holes. - public ComplexPolygon(IShape outline, params IShape[] holes) - : this(new[] { outline }, holes) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The outlines. - /// The holes. - public ComplexPolygon(IShape[] outlines, IShape[] holes) - { - Guard.NotNull(outlines, nameof(outlines)); - Guard.MustBeGreaterThanOrEqualTo(outlines.Length, 1, nameof(outlines)); - - this.MaxIntersections = this.FixAndSetShapes(outlines, holes); - - float minX = this.shapes.Min(x => x.Bounds.Left); - float maxX = this.shapes.Max(x => x.Bounds.Right); - float minY = this.shapes.Min(x => x.Bounds.Top); - float maxY = this.shapes.Max(x => x.Bounds.Bottom); - - this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY); - } - - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - public RectangleF Bounds { get; } - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - public int MaxIntersections { get; } - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// Returns the distance from thr shape to the point - /// - /// - /// Due to the clipping we did during construction we know that out shapes do not overlap at there edges - /// therefore for apoint to be in more that one we must be in a hole of another, theoretically this could - /// then flip again to be in a outlin inside a hole inside an outline :) - /// - float IShape.Distance(Vector2 point) - { - float dist = float.MaxValue; - bool inside = false; - foreach (IShape shape in this.shapes) - { - float d = shape.Distance(point); - - if (d <= 0) - { - // we are inside a poly - d = -d; // flip the sign - inside ^= true; // flip the inside flag - } - - if (d < dist) - { - dist = d; - } - } - - if (inside) - { - return -dist; - } - - return dist; - } - - /// - /// Based on a line described by and - /// populate a buffer for all points on all the polygons, that make up this complex shape, - /// that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - int totalAdded = 0; - for (int i = 0; i < this.shapes.Length; i++) - { - int added = this.shapes[i].FindIntersections(start, end, buffer, count, offset); - count -= added; - offset += added; - totalAdded += added; - } - - return totalAdded; - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return this.paths.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.GetEnumerator(); - } - - private void AddPoints(Clipper clipper, IShape shape, PolyType polyType) - { - // if the path is already the shape use it directly and skip the path loop. - if (shape is IPath) - { - clipper.AddPath( - (IPath)shape, - polyType); - } - else - { - foreach (IPath path in shape) - { - clipper.AddPath( - path, - polyType); - } - } - } - - private void AddPoints(Clipper clipper, IEnumerable shapes, PolyType polyType) - { - foreach (IShape shape in shapes) - { - this.AddPoints(clipper, shape, polyType); - } - } - - private void ExtractOutlines(PolyNode tree, List shapes, List paths) - { - if (tree.Contour.Any()) - { - // if the source path is set then we clipper retained the full path intact thus we can freely - // use it and get any shape optimisations that are availible. - if (tree.SourcePath != null) - { - shapes.Add((IShape)tree.SourcePath); - paths.Add(tree.SourcePath); - } - else - { - // convert the Clipper Contour from scaled ints back down to the origional size (this is going to be lossy but not significantly) - Polygon polygon = new Polygon(new Paths.LinearLineSegment(tree.Contour.ToArray())); - - shapes.Add(polygon); - paths.Add(polygon); - } - } - - foreach (PolyNode c in tree.Children) - { - this.ExtractOutlines(c, shapes, paths); - } - } - - private int FixAndSetShapes(IEnumerable outlines, IEnumerable holes) - { - Clipper clipper = new Clipper(); - - // add the outlines and the holes to clipper, scaling up from the float source to the int based system clipper uses - this.AddPoints(clipper, outlines, PolyType.Subject); - this.AddPoints(clipper, holes, PolyType.Clip); - - PolyTree tree = clipper.Execute(); - - List shapes = new List(); - List paths = new List(); - - // convert the 'tree' back to paths - this.ExtractOutlines(tree, shapes, paths); - this.shapes = shapes.ToArray(); - this.paths = paths.ToArray(); - - int intersections = 0; - foreach (IShape s in this.shapes) - { - intersections += s.MaxIntersections; - } - - return intersections; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/IShape.cs b/src/ImageSharp.Drawing/Shapes/IShape.cs deleted file mode 100644 index 242e3bd8ec..0000000000 --- a/src/ImageSharp.Drawing/Shapes/IShape.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System.Collections.Generic; - using System.Numerics; - using Paths; - - /// - /// Represents a closed set of paths making up a single shape. - /// - public interface IShape : IEnumerable - { - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - RectangleF Bounds { get; } - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - int MaxIntersections { get; } - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// Returns the distance from the shape to the point - /// - float Distance(Vector2 point); - - /// - /// Based on a line described by and - /// populate a buffer for all points on the polygon that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset); - } -} diff --git a/src/ImageSharp.Drawing/Shapes/LinearPolygon.cs b/src/ImageSharp.Drawing/Shapes/LinearPolygon.cs deleted file mode 100644 index 30a30c20f9..0000000000 --- a/src/ImageSharp.Drawing/Shapes/LinearPolygon.cs +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System.Collections; - using System.Collections.Generic; - using System.Numerics; - using Paths; - - /// - /// Represents a polygon made up exclusivly of a single Linear path. - /// - public sealed class LinearPolygon : IShape - { - private Polygon innerPolygon; - - /// - /// Initializes a new instance of the class. - /// - /// The points. - public LinearPolygon(params Vector2[] points) - { - this.innerPolygon = new Polygon(new LinearLineSegment(points)); - } - - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - public RectangleF Bounds => this.innerPolygon.Bounds; - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - public int MaxIntersections - { - get - { - return this.innerPolygon.MaxIntersections; - } - } - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// Returns the distance from the shape to the point - /// - public float Distance(Vector2 point) => this.innerPolygon.Distance(point); - - /// - /// Based on a line described by and - /// populate a buffer for all points on the polygon that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - return this.innerPolygon.FindIntersections(start, end, buffer, count, offset); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() => this.innerPolygon.GetEnumerator(); - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() => this.innerPolygon.GetEnumerator(); - } -} diff --git a/src/ImageSharp.Drawing/Shapes/Polygon.cs b/src/ImageSharp.Drawing/Shapes/Polygon.cs deleted file mode 100644 index 86c3c9ee43..0000000000 --- a/src/ImageSharp.Drawing/Shapes/Polygon.cs +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System.Collections; - using System.Collections.Generic; - using System.Numerics; - - using Paths; - - /// - /// A shape made up of a single path made up of one of more s - /// - public sealed class Polygon : IShape, IPath - { - private readonly InternalPath innerPath; - private readonly IEnumerable pathCollection; - - /// - /// Initializes a new instance of the class. - /// - /// The segments. - public Polygon(params ILineSegment[] segments) - { - this.innerPath = new InternalPath(segments, true); - this.pathCollection = new[] { this }; - } - - /// - /// Initializes a new instance of the class. - /// - /// The segment. - public Polygon(ILineSegment segment) - { - this.innerPath = new InternalPath(segment, true); - this.pathCollection = new[] { this }; - } - - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - public RectangleF Bounds => this.innerPath.Bounds; - - /// - /// Gets the length of the path - /// - /// - /// The length. - /// - public float Length => this.innerPath.Length; - - /// - /// Gets a value indicating whether this instance is closed. - /// - /// - /// true if this instance is closed; otherwise, false. - /// - public bool IsClosed => true; - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - public int MaxIntersections => this.innerPath.Points.Length; - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// The distance of the point away from the shape - /// - public float Distance(Vector2 point) - { - bool isInside = this.innerPath.PointInPolygon(point); - - float distance = this.innerPath.DistanceFromPath(point).DistanceFromPath; - if (isInside) - { - return -distance; - } - - return distance; - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return this.pathCollection.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.pathCollection.GetEnumerator(); - } - - /// - /// Calcualtes the distance along and away from the path for a specified point. - /// - /// The point along the path. - /// - /// distance metadata about the point. - /// - PointInfo IPath.Distance(Vector2 point) - { - return this.innerPath.DistanceFromPath(point); - } - - /// - /// Returns the current shape as a simple linear path. - /// - /// - /// Returns the current as simple linear path. - /// - public Vector2[] AsSimpleLinearPath() - { - return this.innerPath.Points; - } - - /// - /// Based on a line described by and - /// populate a buffer for all points on the polygon that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - return this.innerPath.FindIntersections(start, end, buffer, count, offset); - } - } -} diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs deleted file mode 100644 index c13acec8f1..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs +++ /dev/null @@ -1,3860 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Library to clip polygons. - /// - internal class Clipper - { - private const double HorizontalDeltaLimit = -3.4E+38; - private const int Skip = -2; - private const int Unassigned = -1; // InitOptions that can be passed to the constructor ... - - private Maxima maxima; - private TEdge sortedEdges; - private List intersectList; - private IComparer intersectNodeComparer = new IntersectNodeSort(); - private bool executeLocked; - - private List joins; - private List ghostJoins; - private bool usingPolyTree; - private LocalMinima minimaList = null; - private LocalMinima currentLM = null; - private List> edges = new List>(); - private Scanbeam scanbeam; - private List polyOuts; - private TEdge activeEdges; - - /// - /// Initializes a new instance of the class. - /// - public Clipper() - { - this.scanbeam = null; - this.maxima = null; - this.activeEdges = null; - this.sortedEdges = null; - this.intersectList = new List(); - this.executeLocked = false; - this.usingPolyTree = false; - this.polyOuts = new List(); - this.joins = new List(); - this.ghostJoins = new List(); - } - - /// - /// Node types - /// - private enum NodeType - { - /// - /// Any - /// - Any, - - /// - /// The open - /// - Open, - - /// - /// The closed - /// - Closed - } - - /// - /// Adds the path. - /// - /// The path. - /// Type of the poly. - /// True if the path was added. - /// AddPath: Open paths have been disabled. - public bool AddPath(IPath path, PolyType polyType) - { - var pg = path.AsSimpleLinearPath(); - - int highI = pg.Length - 1; - while (highI > 0 && (pg[highI] == pg[0])) - { - --highI; - } - - while (highI > 0 && (pg[highI] == pg[highI - 1])) - { - --highI; - } - - if (highI < 2) - { - return false; - } - - // create a new edge array ... - List edges = new List(highI + 1); - for (int i = 0; i <= highI; i++) - { - edges.Add(new TEdge() { SourcePath = path }); - } - - bool isFlat = true; - - // 1. Basic (first) edge initialization ... - edges[1].Curr = pg[1]; - - InitEdge(edges[0], edges[1], edges[highI], pg[0]); - InitEdge(edges[highI], edges[0], edges[highI - 1], pg[highI]); - for (int i = highI - 1; i >= 1; --i) - { - InitEdge(edges[i], edges[i + 1], edges[i - 1], pg[i]); - } - - TEdge eStart = edges[0]; - - // 2. Remove duplicate vertices, and (when closed) collinear edges ... - TEdge edge = eStart, eLoopStop = eStart; - while (true) - { - // nb: allows matching start and end points when not Closed ... - if (edge.Curr == edge.Next.Curr) - { - if (edge == edge.Next) - { - break; - } - - if (edge == eStart) - { - eStart = edge.Next; - } - - edge = RemoveEdge(edge); - eLoopStop = edge; - continue; - } - - if (edge.Prev == edge.Next) - { - break; // only two vertices - } - else if (SlopesEqual(edge.Prev.Curr, edge.Curr, edge.Next.Curr)) - { - // Collinear edges are allowed for open paths but in closed paths - // the default is to merge adjacent collinear edges into a single edge. - // However, if the PreserveCollinear property is enabled, only overlapping - // collinear edges (ie spikes) will be removed from closed paths. - if (edge == eStart) - { - eStart = edge.Next; - } - - edge = RemoveEdge(edge); - edge = edge.Prev; - eLoopStop = edge; - continue; - } - - edge = edge.Next; - if (edge == eLoopStop) - { - break; - } - } - - if (edge.Prev == edge.Next) - { - return false; - } - - // 3. Do second stage of edge initialization ... - edge = eStart; - do - { - this.InitEdge2(edge, polyType); - edge = edge.Next; - if (isFlat && edge.Curr.Y != eStart.Curr.Y) - { - isFlat = false; - } - } - while (edge != eStart); - - // 4. Finally, add edge bounds to LocalMinima list ... - // Totally flat paths must be handled differently when adding them - // to LocalMinima list to avoid endless loops etc ... - if (isFlat) - { - return false; - } - - this.edges.Add(edges); - bool leftBoundIsForward; - TEdge emIn = null; - - // workaround to avoid an endless loop in the while loop below when - // open paths have matching start and end points ... - if (edge.Prev.Bot == edge.Prev.Top) - { - edge = edge.Next; - } - - while (true) - { - edge = FindNextLocMin(edge); - if (edge == emIn) - { - break; - } - else if (emIn == null) - { - emIn = edge; - } - - // E and E.Prev now share a local minima (left aligned if horizontal). - // Compare their slopes to find which starts which bound ... - LocalMinima locMin = new LocalMinima(); - locMin.Next = null; - locMin.Y = edge.Bot.Y; - if (edge.Dx < edge.Prev.Dx) - { - locMin.LeftBound = edge.Prev; - locMin.RightBound = edge; - leftBoundIsForward = false; // Q.nextInLML = Q.prev - } - else - { - locMin.LeftBound = edge; - locMin.RightBound = edge.Prev; - leftBoundIsForward = true; // Q.nextInLML = Q.next - } - - locMin.LeftBound.Side = EdgeSide.Left; - locMin.RightBound.Side = EdgeSide.Right; - - if (locMin.LeftBound.Next == locMin.RightBound) - { - locMin.LeftBound.WindDelta = -1; - } - else - { - locMin.LeftBound.WindDelta = 1; - } - - locMin.RightBound.WindDelta = -locMin.LeftBound.WindDelta; - - edge = this.ProcessBound(locMin.LeftBound, leftBoundIsForward); - if (edge.OutIdx == Skip) - { - edge = this.ProcessBound(edge, leftBoundIsForward); - } - - TEdge edge2 = this.ProcessBound(locMin.RightBound, !leftBoundIsForward); - if (edge2.OutIdx == Skip) - { - edge2 = this.ProcessBound(edge2, !leftBoundIsForward); - } - - if (locMin.LeftBound.OutIdx == Skip) - { - locMin.LeftBound = null; - } - else if (locMin.RightBound.OutIdx == Skip) - { - locMin.RightBound = null; - } - - this.InsertLocalMinima(locMin); - if (!leftBoundIsForward) - { - edge = edge2; - } - } - - return true; - } - - /// - /// Executes the specified clip type. - /// - /// - /// Returns the polytree containing the converted polygons. - /// - public PolyTree Execute() - { - PolyTree polytree = new PolyTree(); - - if (this.executeLocked) - { - return null; - } - - this.executeLocked = true; - this.usingPolyTree = true; - bool succeeded; - try - { - succeeded = this.ExecuteInternal(); - - // build the return polygons ... - if (succeeded) - { - this.BuildResult2(polytree); - } - } - finally - { - this.DisposeAllPolyPts(); - this.executeLocked = false; - } - - if (succeeded) - { - return polytree; - } - - return null; - } - - private static float Round(double value) - { - return value < 0 ? (float)(value - 0.5) : (float)(value + 0.5); - } - - private static float TopX(TEdge edge, float currentY) - { - if (currentY == edge.Top.Y) - { - return edge.Top.X; - } - - return edge.Bot.X + Round(edge.Dx * (currentY - edge.Bot.Y)); - } - - private static void AddPolyNodeToPaths(PolyNode polynode, NodeType nt, List> paths) - { - bool match = true; - switch (nt) - { - case NodeType.Open: return; - case NodeType.Closed: match = !polynode.IsOpen; break; - default: break; - } - - if (polynode.Polygon.Count > 0 && match) - { - paths.Add(polynode.Polygon); - } - - foreach (PolyNode pn in polynode.Children) - { - AddPolyNodeToPaths(pn, nt, paths); - } - } - - private static double DistanceFromLineSqrd(Vector2 pt, Vector2 ln1, Vector2 ln2) - { - // The equation of a line in general form (Ax + By + C = 0) - // given 2 points (x¹,y¹) & (x²,y²) is ... - // (y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 - // A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ - // perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) - // see http://en.wikipedia.org/wiki/Perpendicular_distance - double a = ln1.Y - ln2.Y; - double b = ln2.X - ln1.X; - double c = (a * ln1.X) + (b * ln1.Y); - c = (a * pt.X) + (b * pt.Y) - c; - return (c * c) / ((a * a) + (b * b)); - } - - private static bool SlopesNearCollinear(Vector2 pt1, Vector2 pt2, Vector2 pt3, double distSqrd) - { - // this function is more accurate when the point that's GEOMETRICALLY - // between the other 2 points is the one that's tested for distance. - // nb: with 'spikes', either pt1 or pt3 is geometrically between the other pts - if (Math.Abs(pt1.X - pt2.X) > Math.Abs(pt1.Y - pt2.Y)) - { - if ((pt1.X > pt2.X) == (pt1.X < pt3.X)) - { - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - } - else if ((pt2.X > pt1.X) == (pt2.X < pt3.X)) - { - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - } - else - { - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - } - else - { - if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y)) - { - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - } - else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y)) - { - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - } - else - { - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - } - } - - private static bool PointsAreClose(Vector2 pt1, Vector2 pt2, double distSqrd) - { - return Vector2.DistanceSquared(pt1, pt2) <= distSqrd; - } - - private static OutPt ExcludeOp(OutPt op) - { - OutPt result = op.Prev; - result.Next = op.Next; - op.Next.Prev = result; - result.Idx = 0; - return result; - } - - private static void FixHoleLinkage(OutRec outRec) - { - // skip if an outermost polygon or - // already already points to the correct FirstLeft ... - if (outRec.FirstLeft == null || - (outRec.IsHole != outRec.FirstLeft.IsHole && - outRec.FirstLeft.Pts != null)) - { - return; - } - - OutRec orfl = outRec.FirstLeft; - while (orfl != null && ((orfl.IsHole == outRec.IsHole) || orfl.Pts == null)) - { - orfl = orfl.FirstLeft; - } - - outRec.FirstLeft = orfl; - } - - // See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos - // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf - private static int PointInPolygon(Vector2 pt, OutPt op) - { - // returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - OutPt startOp = op; - float ptx = pt.X, pty = pt.Y; - float poly0x = op.Pt.X, poly0y = op.Pt.Y; - do - { - op = op.Next; - float poly1x = op.Pt.X, poly1y = op.Pt.Y; - - if (poly1y == pty) - { - if ((poly1x == ptx) || (poly0y == pty && - ((poly1x > ptx) == (poly0x < ptx)))) - { - return -1; - } - } - - if ((poly0y < pty) != (poly1y < pty)) - { - if (poly0x >= ptx) - { - if (poly1x > ptx) - { - result = 1 - result; - } - else - { - double d = (double)((poly0x - ptx) * (poly1y - pty)) - - (double)((poly1x - ptx) * (poly0y - pty)); - if (d == 0) - { - return -1; - } - - if ((d > 0) == (poly1y > poly0y)) - { - result = 1 - result; - } - } - } - else - { - if (poly1x > ptx) - { - double d = (double)((poly0x - ptx) * (poly1y - pty)) - (double)((poly1x - ptx) * (poly0y - pty)); - if (d == 0) - { - return -1; - } - - if ((d > 0) == (poly1y > poly0y)) - { - result = 1 - result; - } - } - } - } - - poly0x = poly1x; - poly0y = poly1y; - } - while (startOp != op); - - return result; - } - - private static bool Poly2ContainsPoly1(OutPt outPt1, OutPt outPt2) - { - OutPt op = outPt1; - do - { - // nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon - int res = PointInPolygon(op.Pt, outPt2); - if (res >= 0) - { - return res > 0; - } - - op = op.Next; - } - while (op != outPt1); - return true; - } - - private static void SwapSides(TEdge edge1, TEdge edge2) - { - EdgeSide side = edge1.Side; - edge1.Side = edge2.Side; - edge2.Side = side; - } - - private static void SwapPolyIndexes(TEdge edge1, TEdge edge2) - { - int outIdx = edge1.OutIdx; - edge1.OutIdx = edge2.OutIdx; - edge2.OutIdx = outIdx; - } - - private static double GetDx(Vector2 pt1, Vector2 pt2) - { - if (pt1.Y == pt2.Y) - { - return HorizontalDeltaLimit; - } - else - { - return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); - } - } - - private static bool HorzSegmentsOverlap(float seg1a, float seg1b, float seg2a, float seg2b) - { - if (seg1a > seg1b) - { - Swap(ref seg1a, ref seg1b); - } - - if (seg2a > seg2b) - { - Swap(ref seg2a, ref seg2b); - } - - return (seg1a < seg2b) && (seg2a < seg1b); - } - - private static TEdge FindNextLocMin(TEdge edge) - { - TEdge edge2; - while (true) - { - while (edge.Bot != edge.Prev.Bot || edge.Curr == edge.Top) - { - edge = edge.Next; - } - - if (edge.Dx != HorizontalDeltaLimit && edge.Prev.Dx != HorizontalDeltaLimit) - { - break; - } - - while (edge.Prev.Dx == HorizontalDeltaLimit) - { - edge = edge.Prev; - } - - edge2 = edge; - while (edge.Dx == HorizontalDeltaLimit) - { - edge = edge.Next; - } - - if (edge.Top.Y == edge.Prev.Bot.Y) - { - continue; // ie just an intermediate horz. - } - - if (edge2.Prev.Bot.X < edge.Bot.X) - { - edge = edge2; - } - - break; - } - - return edge; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(ref float val1, ref float val2) - { - float tmp = val1; - val1 = val2; - val2 = tmp; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsHorizontal(TEdge e) - { - return e.Delta.Y == 0; - } - - private static bool SlopesEqual(TEdge e1, TEdge e2) - { - return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y; - } - - private static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3) - { - var dif12 = pt1 - pt2; - var dif23 = pt2 - pt3; - return (dif12.Y * dif23.X) - (dif12.X * dif23.Y) == 0; - } - - private static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3, Vector2 pt4) - { - var dif12 = pt1 - pt2; - var dif34 = pt3 - pt4; - - return (dif12.Y * dif34.X) - (dif12.X * dif34.Y) == 0; - } - - private static void InitEdge(TEdge e, TEdge eNext, TEdge ePrev, Vector2 pt) - { - e.Next = eNext; - e.Prev = ePrev; - e.Curr = pt; - e.OutIdx = Unassigned; - } - - private static OutRec ParseFirstLeft(OutRec firstLeft) - { - while (firstLeft != null && firstLeft.Pts == null) - { - firstLeft = firstLeft.FirstLeft; - } - - return firstLeft; - } - - private static bool Pt2IsBetweenPt1AndPt3(Vector2 pt1, Vector2 pt2, Vector2 pt3) - { - if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) - { - return false; - } - else if (pt1.X != pt3.X) - { - return (pt2.X > pt1.X) == (pt2.X < pt3.X); - } - else - { - return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); - } - } - - private static TEdge RemoveEdge(TEdge e) - { - // removes e from double_linked_list (but without removing from memory) - e.Prev.Next = e.Next; - e.Next.Prev = e.Prev; - TEdge result = e.Next; - e.Prev = null; // flag as removed (see ClipperBase.Clear) - return result; - } - - private static void ReverseHorizontal(TEdge e) - { - // swap horizontal edges' top and bottom x's so they follow the natural - // progression of the bounds - ie so their xbots will align with the - // adjoining lower edge. [Helpful in the ProcessHorizontal() method.] - Swap(ref e.Top.X, ref e.Bot.X); - } - - private void InsertMaxima(float x) - { - // double-linked list: sorted ascending, ignoring dups. - Maxima newMax = new Maxima(); - newMax.X = x; - if (this.maxima == null) - { - this.maxima = newMax; - this.maxima.Next = null; - this.maxima.Prev = null; - } - else if (x < this.maxima.X) - { - newMax.Next = this.maxima; - newMax.Prev = null; - this.maxima = newMax; - } - else - { - Maxima m = this.maxima; - while (m.Next != null && (x >= m.Next.X)) - { - m = m.Next; - } - - if (x == m.X) - { - return; // ie ignores duplicates (& CG to clean up newMax) - } - - // insert newMax between m and m.Next ... - newMax.Next = m.Next; - newMax.Prev = m; - if (m.Next != null) - { - m.Next.Prev = newMax; - } - - m.Next = newMax; - } - } - - private bool ExecuteInternal() - { - try - { - this.Reset(); - this.sortedEdges = null; - this.maxima = null; - - float botY, topY; - if (!this.PopScanbeam(out botY)) - { - return false; - } - - this.InsertLocalMinimaIntoAEL(botY); - while (this.PopScanbeam(out topY) || this.LocalMinimaPending()) - { - this.ProcessHorizontals(); - this.ghostJoins.Clear(); - if (!this.ProcessIntersections(topY)) - { - return false; - } - - this.ProcessEdgesAtTopOfScanbeam(topY); - botY = topY; - this.InsertLocalMinimaIntoAEL(botY); - } - - // fix orientations ... - foreach (OutRec outRec in this.polyOuts) - { - if (outRec.Pts == null || outRec.IsOpen) - { - continue; - } - } - - this.JoinCommonEdges(); - - foreach (OutRec outRec in this.polyOuts) - { - if (outRec.Pts == null) - { - continue; - } - else if (outRec.IsOpen) - { - this.FixupOutPolyline(outRec); - } - else - { - this.FixupOutPolygon(outRec); - } - } - - return true; - } - finally - { - this.joins.Clear(); - this.ghostJoins.Clear(); - } - } - - private void DisposeAllPolyPts() - { - for (int i = 0; i < this.polyOuts.Count; ++i) - { - this.DisposeOutRec(i); - } - - this.polyOuts.Clear(); - } - - private void AddJoin(OutPt op1, OutPt op2, Vector2 offPt) - { - Join j = new Join(); - j.OutPt1 = op1; - j.OutPt2 = op2; - j.OffPt = offPt; - this.joins.Add(j); - } - - private void AddGhostJoin(OutPt op, Vector2 offPt) - { - Join j = new Join(); - j.OutPt1 = op; - j.OffPt = offPt; - this.ghostJoins.Add(j); - } - - private void InsertLocalMinimaIntoAEL(float botY) - { - LocalMinima lm; - while (this.PopLocalMinima(botY, out lm)) - { - TEdge lb = lm.LeftBound; - TEdge rb = lm.RightBound; - - OutPt op1 = null; - if (lb == null) - { - this.InsertEdgeIntoAEL(rb, null); - this.SetWindingCount(rb); - if (this.IsContributing(rb)) - { - op1 = this.AddOutPt(rb, rb.Bot); - } - } - else if (rb == null) - { - this.InsertEdgeIntoAEL(lb, null); - this.SetWindingCount(lb); - if (this.IsContributing(lb)) - { - op1 = this.AddOutPt(lb, lb.Bot); - } - - this.InsertScanbeam(lb.Top.Y); - } - else - { - this.InsertEdgeIntoAEL(lb, null); - this.InsertEdgeIntoAEL(rb, lb); - this.SetWindingCount(lb); - rb.WindCnt = lb.WindCnt; - rb.WindCnt2 = lb.WindCnt2; - if (this.IsContributing(lb)) - { - op1 = this.AddLocalMinPoly(lb, rb, lb.Bot); - } - - this.InsertScanbeam(lb.Top.Y); - } - - if (rb != null) - { - if (IsHorizontal(rb)) - { - if (rb.NextInLML != null) - { - this.InsertScanbeam(rb.NextInLML.Top.Y); - } - - this.AddEdgeToSEL(rb); - } - else - { - this.InsertScanbeam(rb.Top.Y); - } - } - - if (lb == null || rb == null) - { - continue; - } - - // if output polygons share an Edge with a horizontal rb, they'll need joining later ... - if (op1 != null && IsHorizontal(rb) && - this.ghostJoins.Count > 0 && rb.WindDelta != 0) - { - for (int i = 0; i < this.ghostJoins.Count; i++) - { - // if the horizontal Rb and a 'ghost' horizontal overlap, then convert - // the 'ghost' join to a real join ready for later ... - Join j = this.ghostJoins[i]; - if (HorzSegmentsOverlap(j.OutPt1.Pt.X, j.OffPt.X, rb.Bot.X, rb.Top.X)) - { - this.AddJoin(j.OutPt1, op1, j.OffPt); - } - } - } - - if (lb.OutIdx >= 0 && lb.PrevInAEL != null && - lb.PrevInAEL.Curr.X == lb.Bot.X && - lb.PrevInAEL.OutIdx >= 0 && - SlopesEqual(lb.PrevInAEL.Curr, lb.PrevInAEL.Top, lb.Curr, lb.Top) && - lb.WindDelta != 0 && lb.PrevInAEL.WindDelta != 0) - { - OutPt op2 = this.AddOutPt(lb.PrevInAEL, lb.Bot); - this.AddJoin(op1, op2, lb.Top); - } - - if (lb.NextInAEL != rb) - { - if (rb.OutIdx >= 0 && rb.PrevInAEL.OutIdx >= 0 && - SlopesEqual(rb.PrevInAEL.Curr, rb.PrevInAEL.Top, rb.Curr, rb.Top) && - rb.WindDelta != 0 && rb.PrevInAEL.WindDelta != 0) - { - OutPt op2 = this.AddOutPt(rb.PrevInAEL, rb.Bot); - this.AddJoin(op1, op2, rb.Top); - } - - TEdge e = lb.NextInAEL; - if (e != null) - { - while (e != rb) - { - // nb: For calculating winding counts etc, IntersectEdges() assumes - // that param1 will be to the right of param2 ABOVE the intersection ... - this.IntersectEdges(rb, e, lb.Curr); // order important here - e = e.NextInAEL; - } - } - } - } - } - - private void InsertEdgeIntoAEL(TEdge edge, TEdge startEdge) - { - if (this.activeEdges == null) - { - edge.PrevInAEL = null; - edge.NextInAEL = null; - this.activeEdges = edge; - } - else if (startEdge == null && this.E2InsertsBeforeE1(this.activeEdges, edge)) - { - edge.PrevInAEL = null; - edge.NextInAEL = this.activeEdges; - this.activeEdges.PrevInAEL = edge; - this.activeEdges = edge; - } - else - { - if (startEdge == null) - { - startEdge = this.activeEdges; - } - - while (startEdge.NextInAEL != null && - !this.E2InsertsBeforeE1(startEdge.NextInAEL, edge)) - { - startEdge = startEdge.NextInAEL; - } - - edge.NextInAEL = startEdge.NextInAEL; - if (startEdge.NextInAEL != null) - { - startEdge.NextInAEL.PrevInAEL = edge; - } - - edge.PrevInAEL = startEdge; - startEdge.NextInAEL = edge; - } - } - - private bool E2InsertsBeforeE1(TEdge e1, TEdge e2) - { - if (e2.Curr.X == e1.Curr.X) - { - if (e2.Top.Y > e1.Top.Y) - { - return e2.Top.X < TopX(e1, e2.Top.Y); - } - else - { - return e1.Top.X > TopX(e2, e1.Top.Y); - } - } - else - { - return e2.Curr.X < e1.Curr.X; - } - } - - private bool IsContributing(TEdge edge) - { - // return false if a subj line has been flagged as inside a subj polygon - if (edge.WindDelta == 0 && edge.WindCnt != 1) - { - return false; - } - - if (edge.PolyTyp == PolyType.Subject) - { - return edge.WindCnt2 == 0; - } - else - { - return edge.WindCnt2 != 0; - } - } - - private void SetWindingCount(TEdge edge) - { - TEdge e = edge.PrevInAEL; - - // find the edge of the same polytype that immediately preceeds 'edge' in AEL - while (e != null && ((e.PolyTyp != edge.PolyTyp) || (e.WindDelta == 0))) - { - e = e.PrevInAEL; - } - - if (e == null) - { - if (edge.WindDelta == 0) - { - edge.WindCnt = 1; - } - else - { - edge.WindCnt = edge.WindDelta; - } - - edge.WindCnt2 = 0; - e = this.activeEdges; // ie get ready to calc WindCnt2 - } - else if (edge.WindDelta == 0) - { - edge.WindCnt = 1; - edge.WindCnt2 = e.WindCnt2; - e = e.NextInAEL; // ie get ready to calc WindCnt2 - } - else - { - // EvenOdd filling ... - if (edge.WindDelta == 0) - { - // are we inside a subj polygon ... - bool inside = true; - TEdge e2 = e.PrevInAEL; - while (e2 != null) - { - if (e2.PolyTyp == e.PolyTyp && e2.WindDelta != 0) - { - inside = !inside; - } - - e2 = e2.PrevInAEL; - } - - edge.WindCnt = inside ? 0 : 1; - } - else - { - edge.WindCnt = edge.WindDelta; - } - - edge.WindCnt2 = e.WindCnt2; - e = e.NextInAEL; // ie get ready to calc WindCnt2 - } - - // update WindCnt2 ... - // EvenOdd filling ... - while (e != edge) - { - if (e.WindDelta != 0) - { - edge.WindCnt2 = edge.WindCnt2 == 0 ? 1 : 0; - } - - e = e.NextInAEL; - } - } - - private void AddEdgeToSEL(TEdge edge) - { - // SEL pointers in PEdge are use to build transient lists of horizontal edges. - // However, since we don't need to worry about processing order, all additions - // are made to the front of the list ... - if (this.sortedEdges == null) - { - this.sortedEdges = edge; - edge.PrevInSEL = null; - edge.NextInSEL = null; - } - else - { - edge.NextInSEL = this.sortedEdges; - edge.PrevInSEL = null; - this.sortedEdges.PrevInSEL = edge; - this.sortedEdges = edge; - } - } - - private bool PopEdgeFromSEL(out TEdge e) - { - // Pop edge from front of SEL (ie SEL is a FILO list) - e = this.sortedEdges; - if (e == null) - { - return false; - } - - TEdge oldE = e; - this.sortedEdges = e.NextInSEL; - if (this.sortedEdges != null) - { - this.sortedEdges.PrevInSEL = null; - } - - oldE.NextInSEL = null; - oldE.PrevInSEL = null; - return true; - } - - private void CopyAELToSEL() - { - TEdge e = this.activeEdges; - this.sortedEdges = e; - while (e != null) - { - e.PrevInSEL = e.PrevInAEL; - e.NextInSEL = e.NextInAEL; - e = e.NextInAEL; - } - } - - private void SwapPositionsInSEL(TEdge edge1, TEdge edge2) - { - if (edge1.NextInSEL == null && edge1.PrevInSEL == null) - { - return; - } - - if (edge2.NextInSEL == null && edge2.PrevInSEL == null) - { - return; - } - - if (edge1.NextInSEL == edge2) - { - TEdge next = edge2.NextInSEL; - if (next != null) - { - next.PrevInSEL = edge1; - } - - TEdge prev = edge1.PrevInSEL; - if (prev != null) - { - prev.NextInSEL = edge2; - } - - edge2.PrevInSEL = prev; - edge2.NextInSEL = edge1; - edge1.PrevInSEL = edge2; - edge1.NextInSEL = next; - } - else if (edge2.NextInSEL == edge1) - { - TEdge next = edge1.NextInSEL; - if (next != null) - { - next.PrevInSEL = edge2; - } - - TEdge prev = edge2.PrevInSEL; - if (prev != null) - { - prev.NextInSEL = edge1; - } - - edge1.PrevInSEL = prev; - edge1.NextInSEL = edge2; - edge2.PrevInSEL = edge1; - edge2.NextInSEL = next; - } - else - { - TEdge next = edge1.NextInSEL; - TEdge prev = edge1.PrevInSEL; - edge1.NextInSEL = edge2.NextInSEL; - if (edge1.NextInSEL != null) - { - edge1.NextInSEL.PrevInSEL = edge1; - } - - edge1.PrevInSEL = edge2.PrevInSEL; - if (edge1.PrevInSEL != null) - { - edge1.PrevInSEL.NextInSEL = edge1; - } - - edge2.NextInSEL = next; - if (edge2.NextInSEL != null) - { - edge2.NextInSEL.PrevInSEL = edge2; - } - - edge2.PrevInSEL = prev; - if (edge2.PrevInSEL != null) - { - edge2.PrevInSEL.NextInSEL = edge2; - } - } - - if (edge1.PrevInSEL == null) - { - this.sortedEdges = edge1; - } - else if (edge2.PrevInSEL == null) - { - this.sortedEdges = edge2; - } - } - - private void AddLocalMaxPoly(TEdge e1, TEdge e2, Vector2 pt) - { - this.AddOutPt(e1, pt); - if (e2.WindDelta == 0) - { - this.AddOutPt(e2, pt); - } - - if (e1.OutIdx == e2.OutIdx) - { - e1.OutIdx = Unassigned; - e2.OutIdx = Unassigned; - } - else if (e1.OutIdx < e2.OutIdx) - { - this.AppendPolygon(e1, e2); - } - else - { - this.AppendPolygon(e2, e1); - } - } - - private OutPt AddLocalMinPoly(TEdge e1, TEdge e2, Vector2 pt) - { - OutPt result; - TEdge e, prevE; - if (IsHorizontal(e2) || (e1.Dx > e2.Dx)) - { - result = this.AddOutPt(e1, pt); - e2.OutIdx = e1.OutIdx; - e1.Side = EdgeSide.Left; - e2.Side = EdgeSide.Right; - e = e1; - if (e.PrevInAEL == e2) - { - prevE = e2.PrevInAEL; - } - else - { - prevE = e.PrevInAEL; - } - } - else - { - result = this.AddOutPt(e2, pt); - e1.OutIdx = e2.OutIdx; - e1.Side = EdgeSide.Right; - e2.Side = EdgeSide.Left; - e = e2; - if (e.PrevInAEL == e1) - { - prevE = e1.PrevInAEL; - } - else - { - prevE = e.PrevInAEL; - } - } - - if (prevE != null && prevE.OutIdx >= 0) - { - float xPrev = TopX(prevE, pt.Y); - float xE = TopX(e, pt.Y); - if ((xPrev == xE) && - (e.WindDelta != 0) && - (prevE.WindDelta != 0) && - SlopesEqual(new Vector2(xPrev, pt.Y), prevE.Top, new Vector2(xE, pt.Y), e.Top)) - { - OutPt outPt = this.AddOutPt(prevE, pt); - this.AddJoin(result, outPt, e.Top); - } - } - - return result; - } - - private OutPt AddOutPt(TEdge e, Vector2 pt) - { - if (e.OutIdx < 0) - { - OutRec outRec = this.CreateOutRec(); - outRec.SourcePath = e.SourcePath; // copy source from edge to outrec - outRec.IsOpen = e.WindDelta == 0; - OutPt newOp = new OutPt(); - outRec.Pts = newOp; - newOp.Idx = outRec.Idx; - newOp.Pt = pt; - newOp.Next = newOp; - newOp.Prev = newOp; - if (!outRec.IsOpen) - { - this.SetHoleState(e, outRec); - } - - e.OutIdx = outRec.Idx; // nb: do this after SetZ ! - return newOp; - } - else - { - OutRec outRec = this.polyOuts[e.OutIdx]; - - if (outRec.SourcePath != e.SourcePath) - { - // this edge was from a different/unknown source - outRec.SourcePath = null; // drop source form output - } - - // OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' - OutPt op = outRec.Pts; - bool toFront = e.Side == EdgeSide.Left; - if (toFront && pt == op.Pt) - { - return op; - } - else if (!toFront && pt == op.Prev.Pt) - { - return op.Prev; - } - - // do we need to move the source to the point??? - OutPt newOp = new OutPt(); - newOp.Idx = outRec.Idx; - newOp.Pt = pt; - newOp.Next = op; - newOp.Prev = op.Prev; - newOp.Prev.Next = newOp; - op.Prev = newOp; - if (toFront) - { - outRec.Pts = newOp; - } - - return newOp; - } - } - - private OutPt GetLastOutPt(TEdge e) - { - OutRec outRec = this.polyOuts[e.OutIdx]; - if (e.Side == EdgeSide.Left) - { - return outRec.Pts; - } - else - { - return outRec.Pts.Prev; - } - } - - private void SetHoleState(TEdge e, OutRec outRec) - { - TEdge e2 = e.PrevInAEL; - TEdge eTmp = null; - while (e2 != null) - { - if (e2.OutIdx >= 0 && e2.WindDelta != 0) - { - if (eTmp == null) - { - eTmp = e2; - } - else if (eTmp.OutIdx == e2.OutIdx) - { - eTmp = null; // paired - } - } - - e2 = e2.PrevInAEL; - } - - if (eTmp == null) - { - outRec.FirstLeft = null; - outRec.IsHole = false; - } - else - { - outRec.FirstLeft = this.polyOuts[eTmp.OutIdx]; - outRec.IsHole = !outRec.FirstLeft.IsHole; - } - } - - private bool FirstIsBottomPt(OutPt btmPt1, OutPt btmPt2) - { - OutPt p = btmPt1.Prev; - while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) - { - p = p.Prev; - } - - double dx1p = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); - p = btmPt1.Next; - while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) - { - p = p.Next; - } - - double dx1n = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); - - p = btmPt2.Prev; - while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) - { - p = p.Prev; - } - - double dx2p = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); - p = btmPt2.Next; - while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) - { - p = p.Next; - } - - double dx2n = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); - - if (Math.Max(dx1p, dx1n) == Math.Max(dx2p, dx2n) && - Math.Min(dx1p, dx1n) == Math.Min(dx2p, dx2n)) - { - return this.Area(btmPt1) > 0; // if otherwise identical use orientation - } - else - { - return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); - } - } - - private OutPt GetBottomPt(OutPt pp) - { - OutPt dups = null; - OutPt p = pp.Next; - while (p != pp) - { - if (p.Pt.Y > pp.Pt.Y) - { - pp = p; - dups = null; - } - else if (p.Pt.Y == pp.Pt.Y && p.Pt.X <= pp.Pt.X) - { - if (p.Pt.X < pp.Pt.X) - { - dups = null; - pp = p; - } - else - { - if (p.Next != pp && p.Prev != pp) - { - dups = p; - } - } - } - - p = p.Next; - } - - if (dups != null) - { - // there appears to be at least 2 vertices at bottomPt so ... - while (dups != p) - { - if (!this.FirstIsBottomPt(p, dups)) - { - pp = dups; - } - - dups = dups.Next; - while (dups.Pt != pp.Pt) - { - dups = dups.Next; - } - } - } - - return pp; - } - - private OutRec GetLowermostRec(OutRec outRec1, OutRec outRec2) - { - // work out which polygon fragment has the correct hole state ... - if (outRec1.BottomPt == null) - { - outRec1.BottomPt = this.GetBottomPt(outRec1.Pts); - } - - if (outRec2.BottomPt == null) - { - outRec2.BottomPt = this.GetBottomPt(outRec2.Pts); - } - - OutPt bPt1 = outRec1.BottomPt; - OutPt bPt2 = outRec2.BottomPt; - if (bPt1.Pt.Y > bPt2.Pt.Y) - { - return outRec1; - } - else if (bPt1.Pt.Y < bPt2.Pt.Y) - { - return outRec2; - } - else if (bPt1.Pt.X < bPt2.Pt.X) - { - return outRec1; - } - else if (bPt1.Pt.X > bPt2.Pt.X) - { - return outRec2; - } - else if (bPt1.Next == bPt1) - { - return outRec2; - } - else if (bPt2.Next == bPt2) - { - return outRec1; - } - else if (this.FirstIsBottomPt(bPt1, bPt2)) - { - return outRec1; - } - else - { - return outRec2; - } - } - - private bool OutRec1RightOfOutRec2(OutRec outRec1, OutRec outRec2) - { - do - { - outRec1 = outRec1.FirstLeft; - if (outRec1 == outRec2) - { - return true; - } - } - while (outRec1 != null); - - return false; - } - - private OutRec GetOutRec(int idx) - { - OutRec outrec = this.polyOuts[idx]; - while (outrec != this.polyOuts[outrec.Idx]) - { - outrec = this.polyOuts[outrec.Idx]; - } - - return outrec; - } - - private void AppendPolygon(TEdge e1, TEdge e2) - { - OutRec outRec1 = this.polyOuts[e1.OutIdx]; - OutRec outRec2 = this.polyOuts[e2.OutIdx]; - - OutRec holeStateRec; - if (this.OutRec1RightOfOutRec2(outRec1, outRec2)) - { - holeStateRec = outRec2; - } - else if (this.OutRec1RightOfOutRec2(outRec2, outRec1)) - { - holeStateRec = outRec1; - } - else - { - holeStateRec = this.GetLowermostRec(outRec1, outRec2); - } - - // get the start and ends of both output polygons and - // join E2 poly onto E1 poly and delete pointers to E2 ... - OutPt p1_lft = outRec1.Pts; - OutPt p1_rt = p1_lft.Prev; - OutPt p2_lft = outRec2.Pts; - OutPt p2_rt = p2_lft.Prev; - - // join e2 poly onto e1 poly and delete pointers to e2 ... - if (e1.Side == EdgeSide.Left) - { - if (e2.Side == EdgeSide.Left) - { - // z y x a b c - this.ReversePolyPtLinks(p2_lft); - p2_lft.Next = p1_lft; - p1_lft.Prev = p2_lft; - p1_rt.Next = p2_rt; - p2_rt.Prev = p1_rt; - outRec1.Pts = p2_rt; - } - else - { - // x y z a b c - p2_rt.Next = p1_lft; - p1_lft.Prev = p2_rt; - p2_lft.Prev = p1_rt; - p1_rt.Next = p2_lft; - outRec1.Pts = p2_lft; - } - } - else - { - if (e2.Side == EdgeSide.Right) - { - // a b c z y x - this.ReversePolyPtLinks(p2_lft); - p1_rt.Next = p2_rt; - p2_rt.Prev = p1_rt; - p2_lft.Next = p1_lft; - p1_lft.Prev = p2_lft; - } - else - { - // a b c x y z - p1_rt.Next = p2_lft; - p2_lft.Prev = p1_rt; - p1_lft.Prev = p2_rt; - p2_rt.Next = p1_lft; - } - } - - outRec1.BottomPt = null; - if (holeStateRec == outRec2) - { - if (outRec2.FirstLeft != outRec1) - { - outRec1.FirstLeft = outRec2.FirstLeft; - } - - outRec1.IsHole = outRec2.IsHole; - } - - outRec2.Pts = null; - outRec2.BottomPt = null; - - outRec2.FirstLeft = outRec1; - - int okIdx = e1.OutIdx; - int obsoleteIdx = e2.OutIdx; - - e1.OutIdx = Unassigned; // nb: safe because we only get here via AddLocalMaxPoly - e2.OutIdx = Unassigned; - - TEdge e = this.activeEdges; - while (e != null) - { - if (e.OutIdx == obsoleteIdx) - { - e.OutIdx = okIdx; - e.Side = e1.Side; - break; - } - - e = e.NextInAEL; - } - - outRec2.Idx = outRec1.Idx; - } - - private void ReversePolyPtLinks(OutPt pp) - { - if (pp == null) - { - return; - } - - OutPt pp1; - OutPt pp2; - pp1 = pp; - do - { - pp2 = pp1.Next; - pp1.Next = pp1.Prev; - pp1.Prev = pp2; - pp1 = pp2; - } - while (pp1 != pp); - } - - private void IntersectEdges(TEdge e1, TEdge e2, Vector2 pt) - { - // e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before - // e2 in AEL except when e1 is being inserted at the intersection point ... - bool e1Contributing = e1.OutIdx >= 0; - bool e2Contributing = e2.OutIdx >= 0; - - // update winding counts... - // assumes that e1 will be to the Right of e2 ABOVE the intersection - if (e1.PolyTyp == e2.PolyTyp) - { - int oldE1WindCnt = e1.WindCnt; - e1.WindCnt = e2.WindCnt; - e2.WindCnt = oldE1WindCnt; - } - else - { - e1.WindCnt2 = (e1.WindCnt2 == 0) ? 1 : 0; - e2.WindCnt2 = (e2.WindCnt2 == 0) ? 1 : 0; - } - - int e1Wc, e2Wc; - e1Wc = Math.Abs(e1.WindCnt); - e2Wc = Math.Abs(e2.WindCnt); - - if (e1Contributing && e2Contributing) - { - if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || - (e1.PolyTyp != e2.PolyTyp)) - { - this.AddLocalMaxPoly(e1, e2, pt); - } - else - { - this.AddOutPt(e1, pt); - this.AddOutPt(e2, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - } - else if (e1Contributing) - { - if (e2Wc == 0 || e2Wc == 1) - { - this.AddOutPt(e1, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - } - else if (e2Contributing) - { - if (e1Wc == 0 || e1Wc == 1) - { - this.AddOutPt(e2, pt); - SwapSides(e1, e2); - SwapPolyIndexes(e1, e2); - } - } - else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) - { - // neither edge is currently contributing ... - float e1Wc2, e2Wc2; - - e1Wc2 = Math.Abs(e1.WindCnt2); - e2Wc2 = Math.Abs(e2.WindCnt2); - - if (e1.PolyTyp != e2.PolyTyp) - { - this.AddLocalMinPoly(e1, e2, pt); - } - else if (e1Wc == 1 && e2Wc == 1) - { - if (((e1.PolyTyp == PolyType.Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || - ((e1.PolyTyp == PolyType.Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) - { - this.AddLocalMinPoly(e1, e2, pt); - } - } - else - { - SwapSides(e1, e2); - } - } - } - - private void ProcessHorizontals() - { - TEdge horzEdge; // m_SortedEdges; - while (this.PopEdgeFromSEL(out horzEdge)) - { - this.ProcessHorizontal(horzEdge); - } - } - - private void GetHorzDirection(TEdge horzEdge, out Direction dir, out float left, out float right) - { - if (horzEdge.Bot.X < horzEdge.Top.X) - { - left = horzEdge.Bot.X; - right = horzEdge.Top.X; - dir = Direction.LeftToRight; - } - else - { - left = horzEdge.Top.X; - right = horzEdge.Bot.X; - dir = Direction.RightToLeft; - } - } - - private void ProcessHorizontal(TEdge horzEdge) - { - Direction dir; - float horzLeft, horzRight; - bool isOpen = horzEdge.WindDelta == 0; - - this.GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); - - TEdge eLastHorz = horzEdge, eMaxPair = null; - while (eLastHorz.NextInLML != null && IsHorizontal(eLastHorz.NextInLML)) - { - eLastHorz = eLastHorz.NextInLML; - } - - if (eLastHorz.NextInLML == null) - { - eMaxPair = this.GetMaximaPair(eLastHorz); - } - - Maxima currMax = this.maxima; - if (currMax != null) - { - // get the first maxima in range (X) ... - if (dir == Direction.LeftToRight) - { - while (currMax != null && currMax.X <= horzEdge.Bot.X) - { - currMax = currMax.Next; - } - - if (currMax != null && currMax.X >= eLastHorz.Top.X) - { - currMax = null; - } - } - else - { - while (currMax.Next != null && currMax.Next.X < horzEdge.Bot.X) - { - currMax = currMax.Next; - } - - if (currMax.X <= eLastHorz.Top.X) - { - currMax = null; - } - } - } - - OutPt op1 = null; - - // loop through consec. horizontal edges - while (true) - { - bool isLastHorz = horzEdge == eLastHorz; - TEdge e = this.GetNextInAEL(horzEdge, dir); - while (e != null) - { - // this code block inserts extra coords into horizontal edges (in output - // polygons) whereever maxima touch these horizontal edges. This helps - // 'simplifying' polygons (ie if the Simplify property is set). - if (currMax != null) - { - if (dir == Direction.LeftToRight) - { - while (currMax != null && currMax.X < e.Curr.X) - { - if (horzEdge.OutIdx >= 0 && !isOpen) - { - this.AddOutPt(horzEdge, new Vector2(currMax.X, horzEdge.Bot.Y)); - } - - currMax = currMax.Next; - } - } - else - { - while (currMax != null && currMax.X > e.Curr.X) - { - if (horzEdge.OutIdx >= 0 && !isOpen) - { - this.AddOutPt(horzEdge, new Vector2(currMax.X, horzEdge.Bot.Y)); - } - - currMax = currMax.Prev; - } - } - } - - if ((dir == Direction.LeftToRight && e.Curr.X > horzRight) || - (dir == Direction.RightToLeft && e.Curr.X < horzLeft)) - { - break; - } - - // Also break if we've got to the end of an intermediate horizontal edge ... - // nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. - if (e.Curr.X == horzEdge.Top.X && horzEdge.NextInLML != null && - e.Dx < horzEdge.NextInLML.Dx) - { - break; - } - - // note: may be done multiple times - if (horzEdge.OutIdx >= 0 && !isOpen) - { - op1 = this.AddOutPt(horzEdge, e.Curr); - TEdge eNextHorz = this.sortedEdges; - while (eNextHorz != null) - { - if (eNextHorz.OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge.Bot.X, horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X)) - { - OutPt op2 = this.GetLastOutPt(eNextHorz); - this.AddJoin(op2, op1, eNextHorz.Top); - } - - eNextHorz = eNextHorz.NextInSEL; - } - - this.AddGhostJoin(op1, horzEdge.Bot); - } - - // OK, so far we're still in range of the horizontal Edge but make sure - // we're at the last of consec. horizontals when matching with eMaxPair - if (e == eMaxPair && isLastHorz) - { - if (horzEdge.OutIdx >= 0) - { - this.AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge.Top); - } - - this.DeleteFromAEL(horzEdge); - this.DeleteFromAEL(eMaxPair); - return; - } - - if (dir == Direction.LeftToRight) - { - Vector2 pt = new Vector2(e.Curr.X, horzEdge.Curr.Y); - this.IntersectEdges(horzEdge, e, pt); - } - else - { - Vector2 pt = new Vector2(e.Curr.X, horzEdge.Curr.Y); - this.IntersectEdges(e, horzEdge, pt); - } - - TEdge eNext = this.GetNextInAEL(e, dir); - this.SwapPositionsInAEL(horzEdge, e); - e = eNext; - } // end while(e != null) - - // Break out of loop if HorzEdge.NextInLML is not also horizontal ... - if (horzEdge.NextInLML == null || !IsHorizontal(horzEdge.NextInLML)) - { - break; - } - - this.UpdateEdgeIntoAEL(ref horzEdge); - if (horzEdge.OutIdx >= 0) - { - this.AddOutPt(horzEdge, horzEdge.Bot); - } - - this.GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); - } - - if (horzEdge.OutIdx >= 0 && op1 == null) - { - op1 = this.GetLastOutPt(horzEdge); - TEdge eNextHorz = this.sortedEdges; - while (eNextHorz != null) - { - if (eNextHorz.OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge.Bot.X, horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X)) - { - OutPt op2 = this.GetLastOutPt(eNextHorz); - this.AddJoin(op2, op1, eNextHorz.Top); - } - - eNextHorz = eNextHorz.NextInSEL; - } - - this.AddGhostJoin(op1, horzEdge.Top); - } - - if (horzEdge.NextInLML != null) - { - if (horzEdge.OutIdx >= 0) - { - op1 = this.AddOutPt(horzEdge, horzEdge.Top); - - this.UpdateEdgeIntoAEL(ref horzEdge); - if (horzEdge.WindDelta == 0) - { - return; - } - - // nb: HorzEdge is no longer horizontal here - TEdge ePrev = horzEdge.PrevInAEL; - TEdge eNext = horzEdge.NextInAEL; - if (ePrev != null && ePrev.Curr.X == horzEdge.Bot.X && - ePrev.Curr.Y == horzEdge.Bot.Y && ePrev.WindDelta != 0 && - (ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && - SlopesEqual(horzEdge, ePrev))) - { - OutPt op2 = this.AddOutPt(ePrev, horzEdge.Bot); - this.AddJoin(op1, op2, horzEdge.Top); - } - else if (eNext != null && eNext.Curr.X == horzEdge.Bot.X && - eNext.Curr.Y == horzEdge.Bot.Y && eNext.WindDelta != 0 && - eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && - SlopesEqual(horzEdge, eNext)) - { - OutPt op2 = this.AddOutPt(eNext, horzEdge.Bot); - this.AddJoin(op1, op2, horzEdge.Top); - } - } - else - { - this.UpdateEdgeIntoAEL(ref horzEdge); - } - } - else - { - if (horzEdge.OutIdx >= 0) - { - this.AddOutPt(horzEdge, horzEdge.Top); - } - - this.DeleteFromAEL(horzEdge); - } - } - - private TEdge GetNextInAEL(TEdge e, Direction direction) - { - return direction == Direction.LeftToRight ? e.NextInAEL : e.PrevInAEL; - } - - private bool IsMaxima(TEdge e, double y) - { - return e != null && e.Top.Y == y && e.NextInLML == null; - } - - private bool IsIntermediate(TEdge e, double y) - { - return e.Top.Y == y && e.NextInLML != null; - } - - private TEdge GetMaximaPair(TEdge e) - { - if ((e.Next.Top == e.Top) && e.Next.NextInLML == null) - { - return e.Next; - } - else if ((e.Prev.Top == e.Top) && e.Prev.NextInLML == null) - { - return e.Prev; - } - else - { - return null; - } - } - - private TEdge GetMaximaPairEx(TEdge e) - { - // as above but returns null if MaxPair isn't in AEL (unless it's horizontal) - TEdge result = this.GetMaximaPair(e); - if (result == null || result.OutIdx == Skip || - ((result.NextInAEL == result.PrevInAEL) && !IsHorizontal(result))) - { - return null; - } - - return result; - } - - private bool ProcessIntersections(float topY) - { - if (this.activeEdges == null) - { - return true; - } - - try - { - this.BuildIntersectList(topY); - if (this.intersectList.Count == 0) - { - return true; - } - - if (this.intersectList.Count == 1 || this.FixupIntersectionOrder()) - { - this.ProcessIntersectList(); - } - else - { - return false; - } - } - catch - { - this.sortedEdges = null; - this.intersectList.Clear(); - throw new ClipperException("ProcessIntersections error"); - } - - this.sortedEdges = null; - return true; - } - - private void BuildIntersectList(float topY) - { - if (this.activeEdges == null) - { - return; - } - - // prepare for sorting ... - TEdge e = this.activeEdges; - this.sortedEdges = e; - while (e != null) - { - e.PrevInSEL = e.PrevInAEL; - e.NextInSEL = e.NextInAEL; - e.Curr.X = TopX(e, topY); - e = e.NextInAEL; - } - - // bubblesort ... - bool isModified = true; - while (isModified && this.sortedEdges != null) - { - isModified = false; - e = this.sortedEdges; - while (e.NextInSEL != null) - { - TEdge eNext = e.NextInSEL; - Vector2 pt; - if (e.Curr.X > eNext.Curr.X) - { - this.IntersectPoint(e, eNext, out pt); - if (pt.Y < topY) - { - pt = new Vector2(TopX(e, topY), topY); - } - - IntersectNode newNode = new IntersectNode(); - newNode.Edge1 = e; - newNode.Edge2 = eNext; - newNode.Pt = pt; - this.intersectList.Add(newNode); - - this.SwapPositionsInSEL(e, eNext); - isModified = true; - } - else - { - e = eNext; - } - } - - if (e.PrevInSEL != null) - { - e.PrevInSEL.NextInSEL = null; - } - else - { - break; - } - } - - this.sortedEdges = null; - } - - private bool EdgesAdjacent(IntersectNode inode) - { - return (inode.Edge1.NextInSEL == inode.Edge2) || - (inode.Edge1.PrevInSEL == inode.Edge2); - } - - private bool FixupIntersectionOrder() - { - // pre-condition: intersections are sorted bottom-most first. - // Now it's crucial that intersections are made only between adjacent edges, - // so to ensure this the order of intersections may need adjusting ... - this.intersectList.Sort(this.intersectNodeComparer); - - this.CopyAELToSEL(); - int cnt = this.intersectList.Count; - for (int i = 0; i < cnt; i++) - { - if (!this.EdgesAdjacent(this.intersectList[i])) - { - int j = i + 1; - while (j < cnt && !this.EdgesAdjacent(this.intersectList[j])) - { - j++; - } - - if (j == cnt) - { - return false; - } - - IntersectNode tmp = this.intersectList[i]; - this.intersectList[i] = this.intersectList[j]; - this.intersectList[j] = tmp; - } - - this.SwapPositionsInSEL(this.intersectList[i].Edge1, this.intersectList[i].Edge2); - } - - return true; - } - - private void ProcessIntersectList() - { - for (int i = 0; i < this.intersectList.Count; i++) - { - IntersectNode iNode = this.intersectList[i]; - { - this.IntersectEdges(iNode.Edge1, iNode.Edge2, iNode.Pt); - this.SwapPositionsInAEL(iNode.Edge1, iNode.Edge2); - } - } - - this.intersectList.Clear(); - } - - private void IntersectPoint(TEdge edge1, TEdge edge2, out Vector2 ip) - { - ip = default(Vector2); - double b1, b2; - - // nb: with very large coordinate values, it's possible for SlopesEqual() to - // return false but for the edge.Dx value be equal due to double precision rounding. - if (edge1.Dx == edge2.Dx) - { - ip.Y = edge1.Curr.Y; - ip.X = TopX(edge1, ip.Y); - return; - } - - if (edge1.Delta.X == 0) - { - ip.X = edge1.Bot.X; - if (IsHorizontal(edge2)) - { - ip.Y = edge2.Bot.Y; - } - else - { - b2 = edge2.Bot.Y - (edge2.Bot.X / edge2.Dx); - ip.Y = Round((ip.X / edge2.Dx) + b2); - } - } - else if (edge2.Delta.X == 0) - { - ip.X = edge2.Bot.X; - if (IsHorizontal(edge1)) - { - ip.Y = edge1.Bot.Y; - } - else - { - b1 = edge1.Bot.Y - (edge1.Bot.X / edge1.Dx); - ip.Y = Round((ip.X / edge1.Dx) + b1); - } - } - else - { - b1 = edge1.Bot.X - (edge1.Bot.Y * edge1.Dx); - b2 = edge2.Bot.X - (edge2.Bot.Y * edge2.Dx); - double q = (b2 - b1) / (edge1.Dx - edge2.Dx); - ip.Y = Round(q); - if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx)) - { - ip.X = Round((edge1.Dx * q) + b1); - } - else - { - ip.X = Round((edge2.Dx * q) + b2); - } - } - - if (ip.Y < edge1.Top.Y || ip.Y < edge2.Top.Y) - { - if (edge1.Top.Y > edge2.Top.Y) - { - ip.Y = edge1.Top.Y; - } - else - { - ip.Y = edge2.Top.Y; - } - - if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx)) - { - ip.X = TopX(edge1, ip.Y); - } - else - { - ip.X = TopX(edge2, ip.Y); - } - } - - // finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ... - if (ip.Y > edge1.Curr.Y) - { - ip.Y = edge1.Curr.Y; - - // better to use the more vertical edge to derive X ... - if (Math.Abs(edge1.Dx) > Math.Abs(edge2.Dx)) - { - ip.X = TopX(edge2, ip.Y); - } - else - { - ip.X = TopX(edge1, ip.Y); - } - } - } - - private void ProcessEdgesAtTopOfScanbeam(float topY) - { - TEdge e = this.activeEdges; - while (e != null) - { - // 1. process maxima, treating them as if they're 'bent' horizontal edges, - // but exclude maxima with horizontal edges. nb: e can't be a horizontal. - bool isMaximaEdge = this.IsMaxima(e, topY); - - if (isMaximaEdge) - { - TEdge eMaxPair = this.GetMaximaPairEx(e); - isMaximaEdge = eMaxPair == null || !IsHorizontal(eMaxPair); - } - - if (isMaximaEdge) - { - TEdge ePrev = e.PrevInAEL; - this.DoMaxima(e); - if (ePrev == null) - { - e = this.activeEdges; - } - else - { - e = ePrev.NextInAEL; - } - } - else - { - // 2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... - if (this.IsIntermediate(e, topY) && IsHorizontal(e.NextInLML)) - { - this.UpdateEdgeIntoAEL(ref e); - if (e.OutIdx >= 0) - { - this.AddOutPt(e, e.Bot); - } - - this.AddEdgeToSEL(e); - } - else - { - e.Curr.X = TopX(e, topY); - e.Curr.Y = topY; - } - - e = e.NextInAEL; - } - } - - // 3. Process horizontals at the Top of the scanbeam ... - this.ProcessHorizontals(); - this.maxima = null; - - // 4. Promote intermediate vertices ... - e = this.activeEdges; - while (e != null) - { - if (this.IsIntermediate(e, topY)) - { - OutPt op = null; - if (e.OutIdx >= 0) - { - op = this.AddOutPt(e, e.Top); - } - - this.UpdateEdgeIntoAEL(ref e); - - // if output polygons share an edge, they'll need joining later ... - TEdge ePrev = e.PrevInAEL; - TEdge eNext = e.NextInAEL; - if (ePrev != null && ePrev.Curr.X == e.Bot.X && - ePrev.Curr.Y == e.Bot.Y && op != null && - ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && - SlopesEqual(e.Curr, e.Top, ePrev.Curr, ePrev.Top) && - (e.WindDelta != 0) && (ePrev.WindDelta != 0)) - { - OutPt op2 = this.AddOutPt(ePrev, e.Bot); - this.AddJoin(op, op2, e.Top); - } - else if (eNext != null && eNext.Curr.X == e.Bot.X && - eNext.Curr.Y == e.Bot.Y && op != null && - eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && - SlopesEqual(e.Curr, e.Top, eNext.Curr, eNext.Top) && - (e.WindDelta != 0) && (eNext.WindDelta != 0)) - { - OutPt op2 = this.AddOutPt(eNext, e.Bot); - this.AddJoin(op, op2, e.Top); - } - } - - e = e.NextInAEL; - } - } - - private void DoMaxima(TEdge e) - { - TEdge eMaxPair = this.GetMaximaPairEx(e); - if (eMaxPair == null) - { - if (e.OutIdx >= 0) - { - this.AddOutPt(e, e.Top); - } - - this.DeleteFromAEL(e); - return; - } - - TEdge eNext = e.NextInAEL; - while (eNext != null && eNext != eMaxPair) - { - this.IntersectEdges(e, eNext, e.Top); - this.SwapPositionsInAEL(e, eNext); - eNext = e.NextInAEL; - } - - if (e.OutIdx == Unassigned && eMaxPair.OutIdx == Unassigned) - { - this.DeleteFromAEL(e); - this.DeleteFromAEL(eMaxPair); - } - else if (e.OutIdx >= 0 && eMaxPair.OutIdx >= 0) - { - if (e.OutIdx >= 0) - { - this.AddLocalMaxPoly(e, eMaxPair, e.Top); - } - - this.DeleteFromAEL(e); - this.DeleteFromAEL(eMaxPair); - } - else - { - throw new ClipperException("DoMaxima error"); - } - } - - private int PointCount(OutPt pts) - { - if (pts == null) - { - return 0; - } - - int result = 0; - OutPt p = pts; - do - { - result++; - p = p.Next; - } - while (p != pts); - return result; - } - - private void BuildResult2(PolyTree polytree) - { - polytree.Clear(); - - // add each output polygon/contour to polytree ... - polytree.AllPolys.Capacity = this.polyOuts.Count; - for (int i = 0; i < this.polyOuts.Count; i++) - { - OutRec outRec = this.polyOuts[i]; - int cnt = this.PointCount(outRec.Pts); - if ((outRec.IsOpen && cnt < 2) || - (!outRec.IsOpen && cnt < 3)) - { - continue; - } - - FixHoleLinkage(outRec); - PolyNode pn = new PolyNode(); - pn.SourcePath = outRec.SourcePath; - polytree.AllPolys.Add(pn); - outRec.PolyNode = pn; - pn.Polygon.Capacity = cnt; - OutPt op = outRec.Pts.Prev; - for (int j = 0; j < cnt; j++) - { - pn.Polygon.Add(op.Pt); - op = op.Prev; - } - } - - // fixup PolyNode links etc ... - polytree.Children.Capacity = this.polyOuts.Count; - for (int i = 0; i < this.polyOuts.Count; i++) - { - OutRec outRec = this.polyOuts[i]; - if (outRec.PolyNode == null) - { - continue; - } - else if (outRec.IsOpen) - { - outRec.PolyNode.IsOpen = true; - polytree.AddChild(outRec.PolyNode); - } - else if (outRec.FirstLeft != null && - outRec.FirstLeft.PolyNode != null) - { - outRec.FirstLeft.PolyNode.AddChild(outRec.PolyNode); - } - else - { - polytree.AddChild(outRec.PolyNode); - } - } - } - - private void FixupOutPolyline(OutRec outrec) - { - OutPt pp = outrec.Pts; - OutPt lastPP = pp.Prev; - while (pp != lastPP) - { - pp = pp.Next; - if (pp.Pt == pp.Prev.Pt) - { - if (pp == lastPP) - { - lastPP = pp.Prev; - } - - OutPt tmpPP = pp.Prev; - tmpPP.Next = pp.Next; - pp.Next.Prev = tmpPP; - pp = tmpPP; - } - } - - if (pp == pp.Prev) - { - outrec.Pts = null; - } - } - - private void FixupOutPolygon(OutRec outRec) - { - // FixupOutPolygon() - removes duplicate points and simplifies consecutive - // parallel edges by removing the middle vertex. - OutPt lastOK = null; - outRec.BottomPt = null; - OutPt pp = outRec.Pts; - while (true) - { - if (pp.Prev == pp || pp.Prev == pp.Next) - { - outRec.Pts = null; - return; - } - - // test for duplicate points and collinear edges ... - if ((pp.Pt == pp.Next.Pt) || (pp.Pt == pp.Prev.Pt) || - SlopesEqual(pp.Prev.Pt, pp.Pt, pp.Next.Pt)) - { - lastOK = null; - pp.Prev.Next = pp.Next; - pp.Next.Prev = pp.Prev; - pp = pp.Prev; - } - else if (pp == lastOK) - { - break; - } - else - { - if (lastOK == null) - { - lastOK = pp; - } - - pp = pp.Next; - } - } - - outRec.Pts = pp; - } - - private OutPt DupOutPt(OutPt outPt, bool insertAfter) - { - OutPt result = new OutPt(); - result.Pt = outPt.Pt; - result.Idx = outPt.Idx; - if (insertAfter) - { - result.Next = outPt.Next; - result.Prev = outPt; - outPt.Next.Prev = result; - outPt.Next = result; - } - else - { - result.Prev = outPt.Prev; - result.Next = outPt; - outPt.Prev.Next = result; - outPt.Prev = result; - } - - return result; - } - - private bool GetOverlap(float a1, float a2, float b1, float b2, out float left, out float right) - { - if (a1 < a2) - { - if (b1 < b2) - { - left = Math.Max(a1, b1); - right = Math.Min(a2, b2); - } - else - { - left = Math.Max(a1, b2); - right = Math.Min(a2, b1); - } - } - else - { - if (b1 < b2) - { - left = Math.Max(a2, b1); - right = Math.Min(a1, b2); - } - else - { - left = Math.Max(a2, b2); - right = Math.Min(a1, b1); - } - } - - return left < right; - } - - private bool JoinHorz(OutPt op1, OutPt op1b, OutPt op2, OutPt op2b, Vector2 pt, bool discardLeft) - { - Direction dir1 = op1.Pt.X > op1b.Pt.X ? Direction.RightToLeft : Direction.LeftToRight; - Direction dir2 = op2.Pt.X > op2b.Pt.X ? Direction.RightToLeft : Direction.LeftToRight; - if (dir1 == dir2) - { - return false; - } - - // When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we - // want Op1b to be on the Right. (And likewise with Op2 and Op2b.) - // So, to facilitate this while inserting Op1b and Op2b ... - // when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, - // otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) - if (dir1 == Direction.LeftToRight) - { - while (op1.Next.Pt.X <= pt.X && - op1.Next.Pt.X >= op1.Pt.X && op1.Next.Pt.Y == pt.Y) - { - op1 = op1.Next; - } - - if (discardLeft && (op1.Pt.X != pt.X)) - { - op1 = op1.Next; - } - - op1b = this.DupOutPt(op1, !discardLeft); - if (op1b.Pt != pt) - { - op1 = op1b; - op1.Pt = pt; - op1b = this.DupOutPt(op1, !discardLeft); - } - } - else - { - while (op1.Next.Pt.X >= pt.X && - op1.Next.Pt.X <= op1.Pt.X && - op1.Next.Pt.Y == pt.Y) - { - op1 = op1.Next; - } - - if (!discardLeft && (op1.Pt.X != pt.X)) - { - op1 = op1.Next; - } - - op1b = this.DupOutPt(op1, discardLeft); - if (op1b.Pt != pt) - { - op1 = op1b; - op1.Pt = pt; - op1b = this.DupOutPt(op1, discardLeft); - } - } - - if (dir2 == Direction.LeftToRight) - { - while (op2.Next.Pt.X <= pt.X && - op2.Next.Pt.X >= op2.Pt.X && - op2.Next.Pt.Y == pt.Y) - { - op2 = op2.Next; - } - - if (discardLeft && (op2.Pt.X != pt.X)) - { - op2 = op2.Next; - } - - op2b = this.DupOutPt(op2, !discardLeft); - if (op2b.Pt != pt) - { - op2 = op2b; - op2.Pt = pt; - op2b = this.DupOutPt(op2, !discardLeft); - } - } - else - { - while (op2.Next.Pt.X >= pt.X && - op2.Next.Pt.X <= op2.Pt.X && - op2.Next.Pt.Y == pt.Y) - { - op2 = op2.Next; - } - - if (!discardLeft && (op2.Pt.X != pt.X)) - { - op2 = op2.Next; - } - - op2b = this.DupOutPt(op2, discardLeft); - if (op2b.Pt != pt) - { - op2 = op2b; - op2.Pt = pt; - op2b = this.DupOutPt(op2, discardLeft); - } - } - - if ((dir1 == Direction.LeftToRight) == discardLeft) - { - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - } - else - { - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - } - - return true; - } - - private bool JoinPoints(Join j, OutRec outRec1, OutRec outRec2) - { - OutPt op1 = j.OutPt1, op1b; - OutPt op2 = j.OutPt2, op2b; - - // There are 3 kinds of joins for output polygons ... - // 1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere - // along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). - // 2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same - // location at the Bottom of the overlapping segment (& Join.OffPt is above). - // 3. StrictlySimple joins where edges touch but are not collinear and where - // Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. - bool isHorizontal = j.OutPt1.Pt.Y == j.OffPt.Y; - - if (isHorizontal && (j.OffPt == j.OutPt1.Pt) && (j.OffPt == j.OutPt2.Pt)) - { - // Strictly Simple join ... - if (outRec1 != outRec2) - { - return false; - } - - op1b = j.OutPt1.Next; - while (op1b != op1 && (op1b.Pt == j.OffPt)) - { - op1b = op1b.Next; - } - - bool reverse1 = op1b.Pt.Y > j.OffPt.Y; - op2b = j.OutPt2.Next; - while (op2b != op2 && (op2b.Pt == j.OffPt)) - { - op2b = op2b.Next; - } - - bool reverse2 = op2b.Pt.Y > j.OffPt.Y; - if (reverse1 == reverse2) - { - return false; - } - - if (reverse1) - { - op1b = this.DupOutPt(op1, false); - op2b = this.DupOutPt(op2, true); - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - else - { - op1b = this.DupOutPt(op1, true); - op2b = this.DupOutPt(op2, false); - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - } - else if (isHorizontal) - { - // treat horizontal joins differently to non-horizontal joins since with - // them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt - // may be anywhere along the horizontal edge. - op1b = op1; - while (op1.Prev.Pt.Y == op1.Pt.Y && op1.Prev != op1b && op1.Prev != op2) - { - op1 = op1.Prev; - } - - while (op1b.Next.Pt.Y == op1b.Pt.Y && op1b.Next != op1 && op1b.Next != op2) - { - op1b = op1b.Next; - } - - if (op1b.Next == op1 || op1b.Next == op2) - { - return false; // a flat 'polygon' - } - - op2b = op2; - while (op2.Prev.Pt.Y == op2.Pt.Y && op2.Prev != op2b && op2.Prev != op1b) - { - op2 = op2.Prev; - } - - while (op2b.Next.Pt.Y == op2b.Pt.Y && op2b.Next != op2 && op2b.Next != op1) - { - op2b = op2b.Next; - } - - if (op2b.Next == op2 || op2b.Next == op1) - { - return false; // a flat 'polygon' - } - - float left, right; - - // Op1 -. Op1b & Op2 -. Op2b are the extremites of the horizontal edges - if (!this.GetOverlap(op1.Pt.X, op1b.Pt.X, op2.Pt.X, op2b.Pt.X, out left, out right)) - { - return false; - } - - // DiscardLeftSide: when overlapping edges are joined, a spike will created - // which needs to be cleaned up. However, we don't want Op1 or Op2 caught up - // on the discard Side as either may still be needed for other joins ... - Vector2 pt; - bool discardLeftSide; - if (op1.Pt.X >= left && op1.Pt.X <= right) - { - pt = op1.Pt; - discardLeftSide = op1.Pt.X > op1b.Pt.X; - } - else if (op2.Pt.X >= left && op2.Pt.X <= right) - { - pt = op2.Pt; - discardLeftSide = op2.Pt.X > op2b.Pt.X; - } - else if (op1b.Pt.X >= left && op1b.Pt.X <= right) - { - pt = op1b.Pt; - discardLeftSide = op1b.Pt.X > op1.Pt.X; - } - else - { - pt = op2b.Pt; - discardLeftSide = op2b.Pt.X > op2.Pt.X; - } - - j.OutPt1 = op1; - j.OutPt2 = op2; - return this.JoinHorz(op1, op1b, op2, op2b, pt, discardLeftSide); - } - else - { - // nb: For non-horizontal joins ... - // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y - // 2. Jr.OutPt1.Pt > Jr.OffPt.Y - - // make sure the polygons are correctly oriented ... - op1b = op1.Next; - while ((op1b.Pt == op1.Pt) && (op1b != op1)) - { - op1b = op1b.Next; - } - - bool reverse1 = (op1b.Pt.Y > op1.Pt.Y) || !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt); - if (reverse1) - { - op1b = op1.Prev; - while ((op1b.Pt == op1.Pt) && (op1b != op1)) - { - op1b = op1b.Prev; - } - - if ((op1b.Pt.Y > op1.Pt.Y) || - !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt)) - { - return false; - } - } - - op2b = op2.Next; - while ((op2b.Pt == op2.Pt) && (op2b != op2)) - { - op2b = op2b.Next; - } - - bool reverse2 = (op2b.Pt.Y > op2.Pt.Y) || !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt); - if (reverse2) - { - op2b = op2.Prev; - while ((op2b.Pt == op2.Pt) && (op2b != op2)) - { - op2b = op2b.Prev; - } - - if ((op2b.Pt.Y > op2.Pt.Y) || - !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt)) - { - return false; - } - } - - if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || - ((outRec1 == outRec2) && (reverse1 == reverse2))) - { - return false; - } - - if (reverse1) - { - op1b = this.DupOutPt(op1, false); - op2b = this.DupOutPt(op2, true); - op1.Prev = op2; - op2.Next = op1; - op1b.Next = op2b; - op2b.Prev = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - else - { - op1b = this.DupOutPt(op1, true); - op2b = this.DupOutPt(op2, false); - op1.Next = op2; - op2.Prev = op1; - op1b.Prev = op2b; - op2b.Next = op1b; - j.OutPt1 = op1; - j.OutPt2 = op1b; - return true; - } - } - } - - private void FixupFirstLefts1(OutRec oldOutRec, OutRec newOutRec) - { - foreach (OutRec outRec in this.polyOuts) - { - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts != null && firstLeft == oldOutRec) - { - if (Poly2ContainsPoly1(outRec.Pts, newOutRec.Pts)) - { - outRec.FirstLeft = newOutRec; - } - } - } - } - - private void FixupFirstLefts2(OutRec innerOutRec, OutRec outerOutRec) - { - // A polygon has split into two such that one is now the inner of the other. - // It's possible that these polygons now wrap around other polygons, so check - // every polygon that's also contained by OuterOutRec's FirstLeft container - // (including nil) to see if they've become inner to the new inner polygon ... - OutRec orfl = outerOutRec.FirstLeft; - foreach (OutRec outRec in this.polyOuts) - { - if (outRec.Pts == null || outRec == outerOutRec || outRec == innerOutRec) - { - continue; - } - - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (firstLeft != orfl && firstLeft != innerOutRec && firstLeft != outerOutRec) - { - continue; - } - - if (Poly2ContainsPoly1(outRec.Pts, innerOutRec.Pts)) - { - outRec.FirstLeft = innerOutRec; - } - else if (Poly2ContainsPoly1(outRec.Pts, outerOutRec.Pts)) - { - outRec.FirstLeft = outerOutRec; - } - else if (outRec.FirstLeft == innerOutRec || outRec.FirstLeft == outerOutRec) - { - outRec.FirstLeft = orfl; - } - } - } - - private void FixupFirstLefts3(OutRec oldOutRec, OutRec newOutRec) - { - // same as FixupFirstLefts1 but doesn't call Poly2ContainsPoly1() - foreach (OutRec outRec in this.polyOuts) - { - OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts != null && outRec.FirstLeft == oldOutRec) - { - outRec.FirstLeft = newOutRec; - } - } - } - - private void JoinCommonEdges() - { - for (int i = 0; i < this.joins.Count; i++) - { - Join join = this.joins[i]; - - OutRec outRec1 = this.GetOutRec(join.OutPt1.Idx); - OutRec outRec2 = this.GetOutRec(join.OutPt2.Idx); - - if (outRec1.Pts == null || outRec2.Pts == null) - { - continue; - } - - if (outRec1.IsOpen || outRec2.IsOpen) - { - continue; - } - - // get the polygon fragment with the correct hole state (FirstLeft) - // before calling JoinPoints() ... - OutRec holeStateRec; - if (outRec1 == outRec2) - { - holeStateRec = outRec1; - } - else if (this.OutRec1RightOfOutRec2(outRec1, outRec2)) - { - holeStateRec = outRec2; - } - else if (this.OutRec1RightOfOutRec2(outRec2, outRec1)) - { - holeStateRec = outRec1; - } - else - { - holeStateRec = this.GetLowermostRec(outRec1, outRec2); - } - - if (!this.JoinPoints(join, outRec1, outRec2)) - { - continue; - } - - if (outRec1 == outRec2) - { - // instead of joining two polygons, we've just created a new one by - // splitting one polygon into two. - outRec1.Pts = join.OutPt1; - outRec1.BottomPt = null; - outRec2 = this.CreateOutRec(); - outRec2.Pts = join.OutPt2; - - // update all OutRec2.Pts Idx's ... - this.UpdateOutPtIdxs(outRec2); - - if (Poly2ContainsPoly1(outRec2.Pts, outRec1.Pts)) - { - // outRec1 contains outRec2 ... - outRec2.IsHole = !outRec1.IsHole; - outRec2.FirstLeft = outRec1; - - if (this.usingPolyTree) - { - this.FixupFirstLefts2(outRec2, outRec1); - } - } - else if (Poly2ContainsPoly1(outRec1.Pts, outRec2.Pts)) - { - // outRec2 contains outRec1 ... - outRec2.IsHole = outRec1.IsHole; - outRec1.IsHole = !outRec2.IsHole; - outRec2.FirstLeft = outRec1.FirstLeft; - outRec1.FirstLeft = outRec2; - - if (this.usingPolyTree) - { - this.FixupFirstLefts2(outRec1, outRec2); - } - } - else - { - // the 2 polygons are completely separate ... - outRec2.IsHole = outRec1.IsHole; - outRec2.FirstLeft = outRec1.FirstLeft; - - // fixup FirstLeft pointers that may need reassigning to OutRec2 - if (this.usingPolyTree) - { - this.FixupFirstLefts1(outRec1, outRec2); - } - } - } - else - { - // joined 2 polygons together ... - outRec2.Pts = null; - outRec2.BottomPt = null; - outRec2.Idx = outRec1.Idx; - - outRec1.IsHole = holeStateRec.IsHole; - if (holeStateRec == outRec2) - { - outRec1.FirstLeft = outRec2.FirstLeft; - } - - outRec2.FirstLeft = outRec1; - - // fixup FirstLeft pointers that may need reassigning to OutRec1 - if (this.usingPolyTree) - { - this.FixupFirstLefts3(outRec2, outRec1); - } - } - } - } - - private void UpdateOutPtIdxs(OutRec outrec) - { - OutPt op = outrec.Pts; - do - { - op.Idx = outrec.Idx; - op = op.Prev; - } - while (op != outrec.Pts); - } - - private void DoSimplePolygons() - { - int i = 0; - while (i < this.polyOuts.Count) - { - OutRec outrec = this.polyOuts[i++]; - OutPt op = outrec.Pts; - if (op == null || outrec.IsOpen) - { - continue; - } - - do - { - // for each Pt in Polygon until duplicate found do ... - OutPt op2 = op.Next; - while (op2 != outrec.Pts) - { - if ((op.Pt == op2.Pt) && op2.Next != op && op2.Prev != op) - { - // split the polygon into two ... - OutPt op3 = op.Prev; - OutPt op4 = op2.Prev; - op.Prev = op4; - op4.Next = op; - op2.Prev = op3; - op3.Next = op2; - - outrec.Pts = op; - OutRec outrec2 = this.CreateOutRec(); - outrec2.Pts = op2; - this.UpdateOutPtIdxs(outrec2); - if (Poly2ContainsPoly1(outrec2.Pts, outrec.Pts)) - { - // OutRec2 is contained by OutRec1 ... - outrec2.IsHole = !outrec.IsHole; - outrec2.FirstLeft = outrec; - if (this.usingPolyTree) - { - this.FixupFirstLefts2(outrec2, outrec); - } - } - else - if (Poly2ContainsPoly1(outrec.Pts, outrec2.Pts)) - { - // OutRec1 is contained by OutRec2 ... - outrec2.IsHole = outrec.IsHole; - outrec.IsHole = !outrec2.IsHole; - outrec2.FirstLeft = outrec.FirstLeft; - outrec.FirstLeft = outrec2; - if (this.usingPolyTree) - { - this.FixupFirstLefts2(outrec, outrec2); - } - } - else - { - // the 2 polygons are separate ... - outrec2.IsHole = outrec.IsHole; - outrec2.FirstLeft = outrec.FirstLeft; - if (this.usingPolyTree) - { - this.FixupFirstLefts1(outrec, outrec2); - } - } - - op2 = op; // ie get ready for the next iteration - } - - op2 = op2.Next; - } - - op = op.Next; - } - while (op != outrec.Pts); - } - } - - private double Area(OutRec outRec) - { - return this.Area(outRec.Pts); - } - - private double Area(OutPt op) - { - OutPt opFirst = op; - if (op == null) - { - return 0; - } - - double a = 0; - do - { - a = a + ((op.Prev.Pt.X + op.Pt.X) * (op.Prev.Pt.Y - op.Pt.Y)); - op = op.Next; - } - while (op != opFirst); - - return a * 0.5; - } - - private void SetDx(TEdge e) - { - e.Delta.X = e.Top.X - e.Bot.X; - e.Delta.Y = e.Top.Y - e.Bot.Y; - if (e.Delta.Y == 0) - { - e.Dx = HorizontalDeltaLimit; - } - else - { - e.Dx = e.Delta.X / e.Delta.Y; - } - } - - private void InsertLocalMinima(LocalMinima newLm) - { - if (this.minimaList == null) - { - this.minimaList = newLm; - } - else if (newLm.Y >= this.minimaList.Y) - { - newLm.Next = this.minimaList; - this.minimaList = newLm; - } - else - { - LocalMinima tmpLm = this.minimaList; - while (tmpLm.Next != null && (newLm.Y < tmpLm.Next.Y)) - { - tmpLm = tmpLm.Next; - } - - newLm.Next = tmpLm.Next; - tmpLm.Next = newLm; - } - } - - private bool PopLocalMinima(float y, out LocalMinima current) - { - current = this.currentLM; - if (this.currentLM != null && this.currentLM.Y == y) - { - this.currentLM = this.currentLM.Next; - return true; - } - - return false; - } - - private void Reset() - { - this.currentLM = this.minimaList; - if (this.currentLM == null) - { - return; // ie nothing to process - } - - // reset all edges ... - this.scanbeam = null; - LocalMinima lm = this.minimaList; - while (lm != null) - { - this.InsertScanbeam(lm.Y); - TEdge e = lm.LeftBound; - if (e != null) - { - e.Curr = e.Bot; - e.OutIdx = Unassigned; - } - - e = lm.RightBound; - if (e != null) - { - e.Curr = e.Bot; - e.OutIdx = Unassigned; - } - - lm = lm.Next; - } - - this.activeEdges = null; - } - - private void InsertScanbeam(float y) - { - // single-linked list: sorted descending, ignoring dups. - if (this.scanbeam == null) - { - this.scanbeam = new Scanbeam(); - this.scanbeam.Next = null; - this.scanbeam.Y = y; - } - else if (y > this.scanbeam.Y) - { - Scanbeam newSb = new Scanbeam(); - newSb.Y = y; - newSb.Next = this.scanbeam; - this.scanbeam = newSb; - } - else - { - Scanbeam sb2 = this.scanbeam; - while (sb2.Next != null && (y <= sb2.Next.Y)) - { - sb2 = sb2.Next; - } - - if (y == sb2.Y) - { - return; // ie ignores duplicates - } - - Scanbeam newSb = new Scanbeam(); - newSb.Y = y; - newSb.Next = sb2.Next; - sb2.Next = newSb; - } - } - - private bool PopScanbeam(out float y) - { - if (this.scanbeam == null) - { - y = 0; - return false; - } - - y = this.scanbeam.Y; - this.scanbeam = this.scanbeam.Next; - return true; - } - - private bool LocalMinimaPending() - { - return this.currentLM != null; - } - - private OutRec CreateOutRec() - { - OutRec result = new OutRec(); - result.Idx = Unassigned; - result.IsHole = false; - result.IsOpen = false; - result.FirstLeft = null; - result.Pts = null; - result.BottomPt = null; - result.PolyNode = null; - this.polyOuts.Add(result); - result.Idx = this.polyOuts.Count - 1; - return result; - } - - private void DisposeOutRec(int index) - { - OutRec outRec = this.polyOuts[index]; - outRec.Pts = null; - outRec = null; - this.polyOuts[index] = null; - } - - private void UpdateEdgeIntoAEL(ref TEdge e) - { - if (e.NextInLML == null) - { - throw new ClipperException("UpdateEdgeIntoAEL: invalid call"); - } - - TEdge aelPrev = e.PrevInAEL; - TEdge aelNext = e.NextInAEL; - e.NextInLML.OutIdx = e.OutIdx; - if (aelPrev != null) - { - aelPrev.NextInAEL = e.NextInLML; - } - else - { - this.activeEdges = e.NextInLML; - } - - if (aelNext != null) - { - aelNext.PrevInAEL = e.NextInLML; - } - - e.NextInLML.Side = e.Side; - e.NextInLML.WindDelta = e.WindDelta; - e.NextInLML.WindCnt = e.WindCnt; - e.NextInLML.WindCnt2 = e.WindCnt2; - e = e.NextInLML; - e.Curr = e.Bot; - e.PrevInAEL = aelPrev; - e.NextInAEL = aelNext; - if (!IsHorizontal(e)) - { - this.InsertScanbeam(e.Top.Y); - } - } - - private void SwapPositionsInAEL(TEdge edge1, TEdge edge2) - { - // check that one or other edge hasn't already been removed from AEL ... - if (edge1.NextInAEL == edge1.PrevInAEL || - edge2.NextInAEL == edge2.PrevInAEL) - { - return; - } - - if (edge1.NextInAEL == edge2) - { - TEdge next = edge2.NextInAEL; - if (next != null) - { - next.PrevInAEL = edge1; - } - - TEdge prev = edge1.PrevInAEL; - if (prev != null) - { - prev.NextInAEL = edge2; - } - - edge2.PrevInAEL = prev; - edge2.NextInAEL = edge1; - edge1.PrevInAEL = edge2; - edge1.NextInAEL = next; - } - else if (edge2.NextInAEL == edge1) - { - TEdge next = edge1.NextInAEL; - if (next != null) - { - next.PrevInAEL = edge2; - } - - TEdge prev = edge2.PrevInAEL; - if (prev != null) - { - prev.NextInAEL = edge1; - } - - edge1.PrevInAEL = prev; - edge1.NextInAEL = edge2; - edge2.PrevInAEL = edge1; - edge2.NextInAEL = next; - } - else - { - TEdge next = edge1.NextInAEL; - TEdge prev = edge1.PrevInAEL; - edge1.NextInAEL = edge2.NextInAEL; - if (edge1.NextInAEL != null) - { - edge1.NextInAEL.PrevInAEL = edge1; - } - - edge1.PrevInAEL = edge2.PrevInAEL; - if (edge1.PrevInAEL != null) - { - edge1.PrevInAEL.NextInAEL = edge1; - } - - edge2.NextInAEL = next; - if (edge2.NextInAEL != null) - { - edge2.NextInAEL.PrevInAEL = edge2; - } - - edge2.PrevInAEL = prev; - if (edge2.PrevInAEL != null) - { - edge2.PrevInAEL.NextInAEL = edge2; - } - } - - if (edge1.PrevInAEL == null) - { - this.activeEdges = edge1; - } - else if (edge2.PrevInAEL == null) - { - this.activeEdges = edge2; - } - } - - private void DeleteFromAEL(TEdge e) - { - TEdge aelPrev = e.PrevInAEL; - TEdge aelNext = e.NextInAEL; - if (aelPrev == null && aelNext == null && (e != this.activeEdges)) - { - return; // already deleted - } - - if (aelPrev != null) - { - aelPrev.NextInAEL = aelNext; - } - else - { - this.activeEdges = aelNext; - } - - if (aelNext != null) - { - aelNext.PrevInAEL = aelPrev; - } - - e.NextInAEL = null; - e.PrevInAEL = null; - } - - private void InitEdge2(TEdge e, PolyType polyType) - { - if (e.Curr.Y >= e.Next.Curr.Y) - { - e.Bot = e.Curr; - e.Top = e.Next.Curr; - } - else - { - e.Top = e.Curr; - e.Bot = e.Next.Curr; - } - - this.SetDx(e); - e.PolyTyp = polyType; - } - - private TEdge ProcessBound(TEdge edge, bool leftBoundIsForward) - { - TEdge eStart, result = edge; - TEdge horz; - - if (result.OutIdx == Skip) - { - // check if there are edges beyond the skip edge in the bound and if so - // create another LocMin and calling ProcessBound once more ... - edge = result; - if (leftBoundIsForward) - { - while (edge.Top.Y == edge.Next.Bot.Y) - { - edge = edge.Next; - } - - while (edge != result && edge.Dx == HorizontalDeltaLimit) - { - edge = edge.Prev; - } - } - else - { - while (edge.Top.Y == edge.Prev.Bot.Y) - { - edge = edge.Prev; - } - - while (edge != result && edge.Dx == HorizontalDeltaLimit) - { - edge = edge.Next; - } - } - - if (edge == result) - { - if (leftBoundIsForward) - { - result = edge.Next; - } - else - { - result = edge.Prev; - } - } - else - { - // there are more edges in the bound beyond result starting with E - if (leftBoundIsForward) - { - edge = result.Next; - } - else - { - edge = result.Prev; - } - - LocalMinima locMin = new LocalMinima(); - locMin.Next = null; - locMin.Y = edge.Bot.Y; - locMin.LeftBound = null; - locMin.RightBound = edge; - edge.WindDelta = 0; - result = this.ProcessBound(edge, leftBoundIsForward); - this.InsertLocalMinima(locMin); - } - - return result; - } - - if (edge.Dx == HorizontalDeltaLimit) - { - // We need to be careful with open paths because this may not be a - // true local minima (ie E may be following a skip edge). - // Also, consecutive horz. edges may start heading left before going right. - if (leftBoundIsForward) - { - eStart = edge.Prev; - } - else - { - eStart = edge.Next; - } - - // ie an adjoining horizontal skip edge - if (eStart.Dx == HorizontalDeltaLimit) - { - if (eStart.Bot.X != edge.Bot.X && eStart.Top.X != edge.Bot.X) - { - ReverseHorizontal(edge); - } - } - else if (eStart.Bot.X != edge.Bot.X) - { - ReverseHorizontal(edge); - } - } - - eStart = edge; - if (leftBoundIsForward) - { - while (result.Top.Y == result.Next.Bot.Y && result.Next.OutIdx != Skip) - { - result = result.Next; - } - - if (result.Dx == HorizontalDeltaLimit && result.Next.OutIdx != Skip) - { - // nb: at the top of a bound, horizontals are added to the bound - // only when the preceding edge attaches to the horizontal's left vertex - // unless a Skip edge is encountered when that becomes the top divide - horz = result; - while (horz.Prev.Dx == HorizontalDeltaLimit) - { - horz = horz.Prev; - } - - if (horz.Prev.Top.X > result.Next.Top.X) - { - result = horz.Prev; - } - } - - while (edge != result) - { - edge.NextInLML = edge.Next; - if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bot.X != edge.Prev.Top.X) - { - ReverseHorizontal(edge); - } - - edge = edge.Next; - } - - if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bot.X != edge.Prev.Top.X) - { - ReverseHorizontal(edge); - } - - result = result.Next; // move to the edge just beyond current bound - } - else - { - while (result.Top.Y == result.Prev.Bot.Y && result.Prev.OutIdx != Skip) - { - result = result.Prev; - } - - if (result.Dx == HorizontalDeltaLimit && result.Prev.OutIdx != Skip) - { - horz = result; - while (horz.Next.Dx == HorizontalDeltaLimit) - { - horz = horz.Next; - } - - if (horz.Next.Top.X == result.Prev.Top.X || horz.Next.Top.X > result.Prev.Top.X) - { - result = horz.Next; - } - } - - while (edge != result) - { - edge.NextInLML = edge.Prev; - if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bot.X != edge.Next.Top.X) - { - ReverseHorizontal(edge); - } - - edge = edge.Prev; - } - - if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bot.X != edge.Next.Top.X) - { - ReverseHorizontal(edge); - } - - result = result.Prev; // move to the edge just beyond current bound - } - - return result; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs deleted file mode 100644 index cefd268aff..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Clipper Exception - /// - /// - internal class ClipperException : Exception - { - /// - /// Initializes a new instance of the class. - /// - /// The description. - public ClipperException(string description) - : base(description) - { - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs deleted file mode 100644 index 5fa877fd4f..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ??? - /// - internal enum Direction - { - /// - /// The right to left - /// - RightToLeft, - - /// - /// The left to right - /// - LeftToRight - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs deleted file mode 100644 index 5093958d15..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal enum EdgeSide - { - /// - /// The left - /// - Left, - - /// - /// The right - /// - Right - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs deleted file mode 100644 index 7cd0562b09..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal class IntersectNode - { -#pragma warning disable SA1401 // Field must be private - /// - /// The edge1 - /// - internal TEdge Edge1; - - /// - /// The edge2 - /// - internal TEdge Edge2; - - /// - /// The pt - /// - internal System.Numerics.Vector2 Pt; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs deleted file mode 100644 index f4524fa9b7..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Compares s - /// - internal class IntersectNodeSort : IComparer - { - /// - /// Compares the specified node1. - /// - /// The node1. - /// The node2. - /// - /// 1 if node2 %gt; node1 - /// -1 if node2 $lt; node1 - /// 0 if same - /// - public int Compare(IntersectNode node1, IntersectNode node2) - { - float i = node2.Pt.Y - node1.Pt.Y; - if (i > 0) - { - return 1; - } - else if (i < 0) - { - return -1; - } - else - { - return 0; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs deleted file mode 100644 index be948fbf74..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal class Join - { -#pragma warning disable SA1401 // Field must be private - /// - /// The out PT1 - /// - internal OutPt OutPt1; - - /// - /// The out PT2 - /// - internal OutPt OutPt2; - - /// - /// The off pt - /// - internal System.Numerics.Vector2 OffPt; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs deleted file mode 100644 index b48a53cab2..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal class LocalMinima - { -#pragma warning disable SA1401 // Field must be private - /// - /// The y - /// - internal float Y; - - /// - /// The left bound - /// - internal TEdge LeftBound; - - /// - /// The right bound - /// - internal TEdge RightBound; - - /// - /// The next - /// - internal LocalMinima Next; - -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs deleted file mode 100644 index 85168e8e80..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal class Maxima - { -#pragma warning disable SA1401 // Field must be private - /// - /// The x - /// - internal float X; - - /// - /// The next - /// - internal Maxima Next; - - /// - /// The previous - /// - internal Maxima Prev; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs deleted file mode 100644 index 8dae5780ad..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// ?? - /// - internal class OutPt - { -#pragma warning disable SA1401 // Field must be private - /// - /// The index - /// - internal int Idx; - - /// - /// The pt - /// - internal System.Numerics.Vector2 Pt; - - /// - /// The next - /// - internal OutPt Next; - - /// - /// The previous - /// - internal OutPt Prev; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs deleted file mode 100644 index 7c2d41a72e..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// OutRec: contains a path in the clipping solution. Edges in the AEL will - /// carry a pointer to an OutRec when they are part of the clipping solution. - /// - internal class OutRec - { -#pragma warning disable SA1401 // Field must be private - /// - /// The source path - /// - internal IPath SourcePath; - - /// - /// The index - /// - internal int Idx; - - /// - /// The is hole - /// - internal bool IsHole; - - /// - /// The is open - /// - internal bool IsOpen; - - /// - /// The first left - /// - internal OutRec FirstLeft; - - /// - /// The PTS - /// - internal OutPt Pts; - - /// - /// The bottom pt - /// - internal OutPt BottomPt; - - /// - /// The poly node - /// - internal PolyNode PolyNode; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs deleted file mode 100644 index 9d9c355040..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Poly Node - /// - internal class PolyNode - { -#pragma warning disable SA1401 // Field must be private - /// - /// The polygon - /// - internal List Polygon = new List(); - - /// - /// The index - /// - internal int Index; - - /// - /// The childs - /// - protected List children = new List(); - - private PolyNode parent; -#pragma warning restore SA1401 // Field must be private - - /// - /// Gets the child count. - /// - /// - /// The child count. - /// - public int ChildCount - { - get { return this.children.Count; } - } - - /// - /// Gets the contour. - /// - /// - /// The contour. - /// - public List Contour - { - get { return this.Polygon; } - } - - /// - /// Gets the childs. - /// - /// - /// The childs. - /// - public List Children - { - get { return this.children; } - } - - /// - /// Gets or sets the parent. - /// - /// - /// The parent. - /// - public PolyNode Parent - { - get { return this.parent; } - internal set { this.parent = value; } - } - - /// - /// Gets a value indicating whether this instance is hole. - /// - /// - /// true if this instance is hole; otherwise, false. - /// - public bool IsHole - { - get { return this.IsHoleNode(); } - } - - /// - /// Gets or sets a value indicating whether this instance is open. - /// - /// - /// true if this instance is open; otherwise, false. - /// - public bool IsOpen { get; set; } - - /// - /// Gets or sets the source path. - /// - /// - /// The source path. - /// - public IPath SourcePath { get; internal set; } - - /// - /// Gets the next. - /// - /// The next node - public PolyNode GetNext() - { - if (this.children.Count > 0) - { - return this.children[0]; - } - else - { - return this.GetNextSiblingUp(); - } - } - - /// - /// Adds the child. - /// - /// The child. - internal void AddChild(PolyNode child) - { - int cnt = this.children.Count; - this.children.Add(child); - child.parent = this; - child.Index = cnt; - } - - /// - /// Gets the next sibling up. - /// - /// The next sibling up - internal PolyNode GetNextSiblingUp() - { - if (this.parent == null) - { - return null; - } - else if (this.Index == this.parent.children.Count - 1) - { - return this.parent.GetNextSiblingUp(); - } - else - { - return this.parent.Children[this.Index + 1]; - } - } - - /// - /// Determines whether [is hole node]. - /// - /// - /// true if [is hole node]; otherwise, false. - /// - private bool IsHoleNode() - { - bool result = true; - PolyNode node = this.parent; - while (node != null) - { - result = !result; - node = node.parent; - } - - return result; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs deleted file mode 100644 index 3c35f389ce..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Poly Tree - /// - /// - internal class PolyTree : PolyNode - { -#pragma warning disable SA1401 // Field must be private - /// - /// All polys - /// - internal List AllPolys = new List(); -#pragma warning restore SA1401 // Field must be private - - /// - /// Gets the total. - /// - /// - /// The total. - /// - public int Total - { - get - { - int result = this.AllPolys.Count; - - // with negative offsets, ignore the hidden outer polygon ... - if (result > 0 && this.Children[0] != this.AllPolys[0]) - { - result--; - } - - return result; - } - } - - /// - /// Clears this instance. - /// - public void Clear() - { - for (int i = 0; i < this.AllPolys.Count; i++) - { - this.AllPolys[i] = null; - } - - this.AllPolys.Clear(); - this.Children.Clear(); - } - - /// - /// Gets the first. - /// - /// the first node - public PolyNode GetFirst() - { - if (this.Children.Count > 0) - { - return this.Children[0]; - } - else - { - return null; - } - } - } -} diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs deleted file mode 100644 index 2a130f509a..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Poly Type - /// - internal enum PolyType - { - /// - /// The subject - /// - Subject, - - /// - /// The clip - /// - Clip - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md b/src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md deleted file mode 100644 index c0f2ff65fb..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Clipper - -License details for code in this folder, this is code original written by **Angus Johnson** - -The license header onthe original file which has now be split across multiple files in this folder. - -``` -/******************************************************************************* -* * -* Author : Angus Johnson * -* Version : 6.4.0 * -* Date : 2 July 2015 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2015 * -* * -* License: * -* Use, modification & distribution is subject to Boost Software License Ver 1. * -* http://www.boost.org/LICENSE_1_0.txt * -* * -* Attributions: * -* The code in this library is an extension of Bala Vatti's clipping algorithm: * -* "A generic solution to polygon clipping" * -* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * -* http://portal.acm.org/citation.cfm?id=129906 * -* * -* Computer graphics and geometric modeling: implementation and algorithms * -* By Max K. Agoston * -* Springer; 1 edition (January 4, 2005) * -* http://books.google.com/books?q=vatti+clipping+agoston * -* * -* See also: * -* "Polygon Offsetting by Computing Winding Numbers" * -* Paper no. DETC2005-85513 pp. 565-575 * -* ASME 2005 International Design Engineering Technical Conferences * -* and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24-28, 2005 , Long Beach, California, USA * -* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * -* * -*******************************************************************************/ -``` \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs deleted file mode 100644 index 28b341004a..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// Scanbeam - /// - internal class Scanbeam // would this work as a struct? - { -#pragma warning disable SA1401 // Field must be private - /// - /// The y - /// - internal float Y; - - /// - /// The next - /// - internal Scanbeam Next; -#pragma warning restore SA1401 // Field must be private - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs b/src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs deleted file mode 100644 index 97f5b2ec7b..0000000000 --- a/src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes.PolygonClipper -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Runtime.CompilerServices; - - using Paths; - - /// - /// TEdge - /// - internal class TEdge - { -#pragma warning disable SA1401 // Field must be private - /// - /// The source path, see if we can link this back later - /// - internal IPath SourcePath; - - /// - /// The bot - /// - internal System.Numerics.Vector2 Bot; - - /// - /// The current (updated for every new scanbeam) - /// - internal System.Numerics.Vector2 Curr; - - /// - /// The top - /// - internal System.Numerics.Vector2 Top; - - /// - /// The delta - /// - internal System.Numerics.Vector2 Delta; - - /// - /// The dx - /// - internal double Dx; - - /// - /// The poly type - /// - internal PolyType PolyTyp; - - /// - /// Side only refers to current side of solution poly - /// - internal EdgeSide Side; - - /// - /// 1 or -1 depending on winding direction - /// - internal int WindDelta; - - /// - /// The winding count - /// - internal int WindCnt; - - /// - /// The winding count of the opposite polytype - /// - internal int WindCnt2; - - /// - /// The out index - /// - internal int OutIdx; - - /// - /// The next - /// - internal TEdge Next; - - /// - /// The previous - /// - internal TEdge Prev; - - /// - /// The next in LML - /// - internal TEdge NextInLML; - - /// - /// The next in ael - /// - internal TEdge NextInAEL; - - /// - /// The previous in ael - /// - internal TEdge PrevInAEL; - - /// - /// The next in sel - /// - internal TEdge NextInSEL; - - /// - /// The previous in sel - /// - internal TEdge PrevInSEL; -#pragma warning restore SA1401 // Field must be - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs b/src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs deleted file mode 100644 index 5002bee406..0000000000 --- a/src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs +++ /dev/null @@ -1,281 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing.Shapes -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Numerics; - using System.Threading.Tasks; - using Paths; - - /// - /// A way of optermising drawing rectangles. - /// - /// - public class RectangularPolygon : IShape, IPath - { - private readonly RectangleF rectangle; - private readonly Vector2 topLeft; - private readonly Vector2 bottomRight; - private readonly Vector2[] points; - private readonly IEnumerable pathCollection; - private readonly float halfLength; - - /// - /// Initializes a new instance of the class. - /// - /// The rect. - public RectangularPolygon(ImageSharp.Rectangle rect) - : this((RectangleF)rect) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The rect. - public RectangularPolygon(ImageSharp.RectangleF rect) - { - this.rectangle = rect; - this.points = new Vector2[4] - { - this.topLeft = new Vector2(rect.Left, rect.Top), - new Vector2(rect.Right, rect.Top), - this.bottomRight = new Vector2(rect.Right, rect.Bottom), - new Vector2(rect.Left, rect.Bottom) - }; - - this.halfLength = this.rectangle.Width + this.rectangle.Height; - this.Length = this.halfLength * 2; - this.pathCollection = new[] { this }; - } - - /// - /// Gets the bounding box of this shape. - /// - /// - /// The bounds. - /// - public RectangleF Bounds => this.rectangle; - - /// - /// Gets a value indicating whether this instance is closed. - /// - /// - /// true if this instance is closed; otherwise, false. - /// - public bool IsClosed => true; - - /// - /// Gets the length of the path - /// - /// - /// The length. - /// - public float Length { get; } - - /// - /// Gets the maximum number intersections that a shape can have when testing a line. - /// - /// - /// The maximum intersections. - /// - public int MaxIntersections => 4; - - /// - /// Calculates the distance along and away from the path for a specified point. - /// - /// The point along the path. - /// - /// Returns details about the point and its distance away from the path. - /// - PointInfo IPath.Distance(Vector2 point) - { - bool inside; // dont care about inside/outside for paths just distance - return this.Distance(point, false, out inside); - } - - /// - /// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds - /// - /// The point. - /// - /// Returns the distance from the shape to the point - /// - public float Distance(Vector2 point) - { - bool insidePoly; - PointInfo result = this.Distance(point, true, out insidePoly); - - // invert the distance from path when inside - return insidePoly ? -result.DistanceFromPath : result.DistanceFromPath; - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return this.pathCollection.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return this.pathCollection.GetEnumerator(); - } - - /// - /// Converts the into a simple linear path.. - /// - /// - /// Returns the current as simple linear path. - /// - public Vector2[] AsSimpleLinearPath() - { - return this.points; - } - - /// - /// Based on a line described by and - /// populate a buffer for all points on the edges of the - /// that the line intersects. - /// - /// The start point of the line. - /// The end point of the line. - /// The buffer that will be populated with intersections. - /// The count. - /// The offset. - /// - /// The number of intersections populated into the buffer. - /// - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - int discovered = 0; - Vector2 startPoint = Vector2.Clamp(start, this.topLeft, this.bottomRight); - Vector2 endPoint = Vector2.Clamp(end, this.topLeft, this.bottomRight); - - if (startPoint == Vector2.Clamp(startPoint, start, end)) - { - // if start closest is within line then its a valid point - discovered++; - buffer[offset++] = startPoint; - } - - if (endPoint == Vector2.Clamp(endPoint, start, end)) - { - // if start closest is within line then its a valid point - discovered++; - buffer[offset++] = endPoint; - } - - return discovered; - } - - private PointInfo Distance(Vector2 point, bool getDistanceAwayOnly, out bool isInside) - { - // point in rectangle - // if after its clamped by the extreams its still the same then it must be inside :) - Vector2 clamped = Vector2.Clamp(point, this.topLeft, this.bottomRight); - isInside = clamped == point; - - float distanceFromEdge = float.MaxValue; - float distanceAlongEdge = 0f; - - if (isInside) - { - // get the absolute distances from the extreams - Vector2 topLeftDist = Vector2.Abs(point - this.topLeft); - Vector2 bottomRightDist = Vector2.Abs(point - this.bottomRight); - - // get the min components - Vector2 minDists = Vector2.Min(topLeftDist, bottomRightDist); - - // and then the single smallest (dont have to worry about direction) - distanceFromEdge = Math.Min(minDists.X, minDists.Y); - - if (!getDistanceAwayOnly) - { - // we need to make clamped the closest point - if (this.topLeft.X + distanceFromEdge == point.X) - { - // closer to lhf - clamped.X = this.topLeft.X; // y is already the same - - // distance along edge is length minus the amout down we are from the top of the rect - distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y); - } - else if (this.topLeft.Y + distanceFromEdge == point.Y) - { - // closer to top - clamped.Y = this.topLeft.Y; // x is already the same - - distanceAlongEdge = clamped.X - this.topLeft.X; - } - else if (this.bottomRight.Y - distanceFromEdge == point.Y) - { - // closer to bottom - clamped.Y = this.bottomRight.Y; // x is already the same - - distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength; - } - else if (this.bottomRight.X - distanceFromEdge == point.X) - { - // closer to rhs - clamped.X = this.bottomRight.X; // x is already the same - - distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width; - } - } - } - else - { - // clamped is the point on the path thats closest no matter what - distanceFromEdge = (clamped - point).Length(); - - if (!getDistanceAwayOnly) - { - // we need to figure out whats the cloests edge now and thus what distance/poitn is closest - if (this.topLeft.X == clamped.X) - { - // distance along edge is length minus the amout down we are from the top of the rect - distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y); - } - else if (this.topLeft.Y == clamped.Y) - { - distanceAlongEdge = clamped.X - this.topLeft.X; - } - else if (this.bottomRight.Y == clamped.Y) - { - distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength; - } - else if (this.bottomRight.X == clamped.X) - { - distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width; - } - } - } - - return new PointInfo - { - SearchPoint = point, - DistanceFromPath = distanceFromEdge, - ClosestPointOnPath = clamped, - DistanceAlongPath = distanceAlongEdge - }; - } - } -} diff --git a/src/ImageSharp.Drawing/project.json b/src/ImageSharp.Drawing/project.json index b974684a5d..f0d4c62432 100644 --- a/src/ImageSharp.Drawing/project.json +++ b/src/ImageSharp.Drawing/project.json @@ -46,6 +46,7 @@ "target": "project", "version": "1.0.0-*" }, + "SixLabors.Shapes": "0.1.0-ci0043", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs index 8e5c18d27a..defb0e65e7 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs @@ -39,7 +39,7 @@ namespace ImageSharp.Benchmarks { using (CoreImage image = new CoreImage(800, 800)) { - image.Fill(CoreColor.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new CoreRectangle(10, 10, 190, 140))); + image.Fill(CoreColor.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)); return new CoreSize(image.Width, image.Height); } @@ -53,10 +53,10 @@ namespace ImageSharp.Benchmarks image.FillPolygon( CoreColor.HotPink, new[] { - new Vector2(10, 10), - new Vector2(200, 10), - new Vector2(200, 150), - new Vector2(10, 150) }); + new Vector2(10, 10), + new Vector2(200, 10), + new Vector2(200, 150), + new Vector2(10, 150) }); return new CoreSize(image.Width, image.Height); } From b8de0584530e527d4351b6ef369eaa32bca50042 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Mon, 30 Jan 2017 21:43:14 +0000 Subject: [PATCH 02/19] added IRegion and droped use of vectors in brushes --- .travis.yml | 4 +- ConsoleApp1/ConsoleApp1.csproj | 8 + ConsoleApp1/Program.cs | 9 + .../Brushes/ImageBrush{TColor}.cs | 20 +- .../Brushes/PatternBrush{TColor}.cs | 18 +- .../Brushes/Processors/BrushApplicator.cs | 16 +- .../Brushes/RecolorBrush{TColor}.cs | 31 +-- .../Brushes/SolidBrush{TColor}.cs | 8 +- src/ImageSharp.Drawing/Draw.cs | 6 +- src/ImageSharp.Drawing/DrawRectangle.cs | 2 +- src/ImageSharp.Drawing/Fill.cs | 4 +- src/ImageSharp.Drawing/FillRectangle.cs | 4 +- src/ImageSharp.Drawing/IDrawableRegion.cs | 24 +++ src/ImageSharp.Drawing/IRegion.cs | 51 +++++ src/ImageSharp.Drawing/Pens/Pen{TColor}.cs | 8 +- .../Pens/Processors/PenApplicator.cs | 9 +- .../{Pens/Processors => }/PointInfo.cs | 7 +- .../Processors/DrawPathProcessor.cs | 75 +------- .../Processors/FillProcessor.cs | 7 +- .../Processors/FillShapeProcessor.cs | 153 +++++---------- .../Processors/PointInfoExtensions.cs | 5 +- src/ImageSharp.Drawing/ShapeRegion.cs | 180 ++++++++++++++++++ src/ImageSharp.Drawing/project.json | 8 +- .../ImageSharp.Sandbox46.csproj | 3 + .../ImageSharp.Tests/Drawing/DrawPathTests.cs | 5 +- .../Drawing/Helpers/BezierPolygon.cs | 71 +++++++ .../Drawing/Helpers/LinearPolygon.cs | 71 +++++++ .../Drawing/LineComplexPolygonTests.cs | 22 ++- .../Drawing/SolidBezierTests.cs | 3 + .../Drawing/SolidComplexPolygonTests.cs | 16 +- .../Drawing/SolidPolygonTests.cs | 9 +- 31 files changed, 596 insertions(+), 261 deletions(-) create mode 100644 ConsoleApp1/ConsoleApp1.csproj create mode 100644 ConsoleApp1/Program.cs create mode 100644 src/ImageSharp.Drawing/IDrawableRegion.cs create mode 100644 src/ImageSharp.Drawing/IRegion.cs rename src/ImageSharp.Drawing/{Pens/Processors => }/PointInfo.cs (81%) create mode 100644 src/ImageSharp.Drawing/ShapeRegion.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs diff --git a/.travis.yml b/.travis.yml index 172079df24..ca8b90a06a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ branches: script: - dotnet restore - - dotnet build -c Release src/*/project.json - - dotnet test tests/ImageSharp.Tests/project.json -c Release -f "netcoreapp1.1" + - dotnet build -c Release src/*/project.csproj + - dotnet test tests/ImageSharp.Tests/project.csproj -c Release -f "netcoreapp1.1" env: global: diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj new file mode 100644 index 0000000000..68b6f24237 --- /dev/null +++ b/ConsoleApp1/ConsoleApp1.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp1.0 + + + \ No newline at end of file diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs new file mode 100644 index 0000000000..104ecf0262 --- /dev/null +++ b/ConsoleApp1/Program.cs @@ -0,0 +1,9 @@ +using System; + +class Program +{ + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs index 9ce235a847..b9bcc2f9a0 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs @@ -82,18 +82,24 @@ namespace ImageSharp.Drawing.Brushes /// /// Gets the color for a single pixel. /// - /// The point. + /// The x. + /// The y. /// /// The color /// - public override TColor GetColor(Vector2 point) + public override TColor this[int x, int y] { - // Offset the requested pixel by the value in the rectangle (the shapes position) - point = point - this.offset; - int x = (int)point.X % this.xLength; - int y = (int)point.Y % this.yLength; + get + { + var point = new Vector2(x, y); - return this.source[x, y]; + // Offset the requested pixel by the value in the rectangle (the shapes position) + point = point - this.offset; + x = (int)point.X % this.xLength; + y = (int)point.Y % this.yLength; + + return this.source[x, y]; + } } /// diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs index 7749f5ba84..3fea53052d 100644 --- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs +++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs @@ -134,17 +134,21 @@ namespace ImageSharp.Drawing.Brushes /// /// Gets the color for a single pixel. - /// - /// The point. + /// # + /// The x. + /// The y. /// - /// The color + /// The Color. /// - public override TColor GetColor(Vector2 point) + public override TColor this[int x, int y] { - int x = (int)point.X % this.xLength; - int y = (int)point.Y % this.stride; + get + { + x = x % this.xLength; + y = y % this.stride; - return this.pattern[x][y]; + return this.pattern[x][y]; + } } /// diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs index 885be57157..9103dfdf66 100644 --- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs @@ -16,16 +16,20 @@ namespace ImageSharp.Drawing.Processors public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush where TColor : struct, IPackedPixel, IEquatable { + /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// Gets the color for a single pixel. /// - public abstract void Dispose(); + /// The x. + /// The y. + /// + /// The color + /// + public abstract TColor this[int x, int y] { get; } /// - /// Gets the color for a single pixel. + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// - /// The point. - /// The color - public abstract TColor GetColor(Vector2 point); + public abstract void Dispose(); } } diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs index 7149f22a01..33403facb2 100644 --- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs +++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs @@ -109,24 +109,31 @@ namespace ImageSharp.Drawing.Brushes /// /// Gets the color for a single pixel. /// - /// The point. + /// The x. + /// The y. /// /// The color /// - public override TColor GetColor(Vector2 point) + public override TColor this[int x, int y] { - // Offset the requested pixel by the value in the rectangle (the shapes position) - TColor result = this.source[(int)point.X, (int)point.Y]; - Vector4 background = result.ToVector4(); - float distance = Vector4.DistanceSquared(background, this.sourceColor); - if (distance <= this.threshold) + get { - var lerpAmount = (this.threshold - distance) / this.threshold; - Vector4 blended = Vector4BlendTransforms.PremultipliedLerp(background, this.targetColor, lerpAmount); - result.PackFromVector4(blended); + // Offset the requested pixel by the value in the rectangle (the shapes position) + TColor result = this.source[x, y]; + Vector4 background = result.ToVector4(); + float distance = Vector4.DistanceSquared(background, this.sourceColor); + if (distance <= this.threshold) + { + var lerpAmount = (this.threshold - distance) / this.threshold; + Vector4 blended = Vector4BlendTransforms.PremultipliedLerp( + background, + this.targetColor, + lerpAmount); + result.PackFromVector4(blended); + } + + return result; } - - return result; } /// diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs index c3e3113992..018c272b7f 100644 --- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs +++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs @@ -67,14 +67,12 @@ namespace ImageSharp.Drawing.Brushes /// /// Gets the color for a single pixel. /// - /// The point. + /// The x. + /// The y. /// /// The color /// - public override TColor GetColor(Vector2 point) - { - return this.color; - } + public override TColor this[int x, int y] => this.color; /// public override void Dispose() diff --git a/src/ImageSharp.Drawing/Draw.cs b/src/ImageSharp.Drawing/Draw.cs index 8c3dbb1b5a..55dba9257d 100644 --- a/src/ImageSharp.Drawing/Draw.cs +++ b/src/ImageSharp.Drawing/Draw.cs @@ -32,7 +32,7 @@ namespace ImageSharp public static Image DrawPolygon(this Image source, IPen pen, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, shape, options)); + return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(shape), options)); } /// @@ -226,7 +226,7 @@ namespace ImageSharp public static Image DrawPath(this Image source, IPen pen, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, path, options)); + return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(path), options)); } /// @@ -240,7 +240,7 @@ namespace ImageSharp public static Image DrawPath(this Image source, IPen pen, IPath path) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, path, GraphicsOptions.Default)); + return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(path), GraphicsOptions.Default)); } /// diff --git a/src/ImageSharp.Drawing/DrawRectangle.cs b/src/ImageSharp.Drawing/DrawRectangle.cs index 17d6d5f368..243aa082d4 100644 --- a/src/ImageSharp.Drawing/DrawRectangle.cs +++ b/src/ImageSharp.Drawing/DrawRectangle.cs @@ -33,7 +33,7 @@ namespace ImageSharp public static Image DrawPolygon(this Image source, IPen pen, RectangleF shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, (IPath)new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options)); + return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height)), options)); } /// diff --git a/src/ImageSharp.Drawing/Fill.cs b/src/ImageSharp.Drawing/Fill.cs index 637950e76d..f94d9ca6f9 100644 --- a/src/ImageSharp.Drawing/Fill.cs +++ b/src/ImageSharp.Drawing/Fill.cs @@ -56,7 +56,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, shape, options)); + return source.Apply(new FillShapeProcessor(brush, new ShapeRegion(shape), options)); } /// @@ -70,7 +70,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, IShape shape) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, shape, GraphicsOptions.Default)); + return source.Apply(new FillShapeProcessor(brush, new ShapeRegion(shape), GraphicsOptions.Default)); } /// diff --git a/src/ImageSharp.Drawing/FillRectangle.cs b/src/ImageSharp.Drawing/FillRectangle.cs index 7749e7c921..d60a5a19d8 100644 --- a/src/ImageSharp.Drawing/FillRectangle.cs +++ b/src/ImageSharp.Drawing/FillRectangle.cs @@ -30,7 +30,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, RectangleF shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options)); + return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options); } /// @@ -44,7 +44,7 @@ namespace ImageSharp public static Image Fill(this Image source, IBrush brush, RectangleF shape) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new FillShapeProcessor(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), GraphicsOptions.Default)); + return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height)); } /// diff --git a/src/ImageSharp.Drawing/IDrawableRegion.cs b/src/ImageSharp.Drawing/IDrawableRegion.cs new file mode 100644 index 0000000000..82e9c39acf --- /dev/null +++ b/src/ImageSharp.Drawing/IDrawableRegion.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + using System.Numerics; + + /// + /// Represents a region with knowledge about its outline. + /// + /// + public interface IDrawableRegion : IRegion + { + /// + /// Gets the point information for the specified x and y location. + /// + /// The x. + /// The y. + /// Information about the point in relation to a drawable edge + PointInfo GetPointInfo(int x, int y); + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/IRegion.cs b/src/ImageSharp.Drawing/IRegion.cs new file mode 100644 index 0000000000..2264a91bee --- /dev/null +++ b/src/ImageSharp.Drawing/IRegion.cs @@ -0,0 +1,51 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + using System.Numerics; + + /// + /// Represents a region of an image. + /// + public interface IRegion + { + /// + /// Gets the maximum number of intersections to could be returned. + /// + /// + /// The maximum intersections. + /// + int MaxIntersections { get; } + + /// + /// Gets the bounds. + /// + /// + /// The bounds. + /// + Rectangle Bounds { get; } + + /// + /// Scans the X axis for intersections. + /// + /// The x. + /// The buffer. + /// The length. + /// The offset. + /// The number of intersections found. + int ScanX(int x, float[] buffer, int length, int offset); + + /// + /// Scans the Y axis for intersections. + /// + /// The position along the y axis to find intersections. + /// The buffer. + /// The length. + /// The offset. + /// The number of intersections found. + int ScanY(int y, float[] buffer, int length, int offset); + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs index bbb3c25597..d0ea55c1e7 100644 --- a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs +++ b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs @@ -144,10 +144,10 @@ namespace ImageSharp.Drawing.Pens this.brush.Dispose(); } - public override ColoredPointInfo GetColor(PointInfo info) + public override ColoredPointInfo GetColor(int x, int y, PointInfo info) { var result = default(ColoredPointInfo); - result.Color = this.brush.GetColor(info.SearchPoint); + result.Color = this.brush[x, y]; if (info.DistanceFromPath < this.halfWidth) { @@ -197,7 +197,7 @@ namespace ImageSharp.Drawing.Pens this.brush.Dispose(); } - public override ColoredPointInfo GetColor(PointInfo info) + public override ColoredPointInfo GetColor(int x, int y, PointInfo info) { var infoResult = default(ColoredPointInfo); infoResult.DistanceFromElement = float.MaxValue; // is really outside the element @@ -207,7 +207,7 @@ namespace ImageSharp.Drawing.Pens // we can treat the DistanceAlongPath and DistanceFromPath as x,y coords for the pattern // we need to calcualte the distance from the outside edge of the pattern // and set them on the ColoredPointInfo along with the color. - infoResult.Color = this.brush.GetColor(info.SearchPoint); + infoResult.Color = this.brush[x, y]; float distanceWAway = 0; diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs index 222598d85f..de680c809c 100644 --- a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs +++ b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Drawing.Processors { using System; + using System.Numerics; /// /// primitive that converts a into a color and a distance away from the drawable part of the path. @@ -30,8 +31,12 @@ namespace ImageSharp.Drawing.Processors /// /// Gets a from a point represented by a . /// + /// The x. + /// The y. /// The information to extract color details about. - /// Returns the color details and distance from a solid bit of the line. - public abstract ColoredPointInfo GetColor(PointInfo info); + /// + /// Returns the color details and distance from a solid bit of the line. + /// + public abstract ColoredPointInfo GetColor(int x, int y, PointInfo info); } } diff --git a/src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs b/src/ImageSharp.Drawing/PointInfo.cs similarity index 81% rename from src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs rename to src/ImageSharp.Drawing/PointInfo.cs index 6fc78b09b6..e222a81469 100644 --- a/src/ImageSharp.Drawing/Pens/Processors/PointInfo.cs +++ b/src/ImageSharp.Drawing/PointInfo.cs @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp.Drawing.Processors +namespace ImageSharp.Drawing { using System; using System.Numerics; @@ -22,10 +22,5 @@ namespace ImageSharp.Drawing.Processors /// The distance from path /// public float DistanceFromPath; - - /// - /// The search point - /// - public Vector2 SearchPoint; } } diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index d6b2f3eb28..bbb5e1ab6c 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -27,64 +27,27 @@ namespace ImageSharp.Drawing.Processors private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor private readonly IPen pen; - private readonly IPath[] paths; - private readonly RectangleF region; + private readonly IDrawableRegion region; private readonly GraphicsOptions options; /// /// Initializes a new instance of the class. /// /// The pen. - /// The shape. + /// The region. /// The options. - public DrawPathProcessor(IPen pen, IShape shape, GraphicsOptions options) - : this(pen, shape.Paths, options) + public DrawPathProcessor(IPen pen, IDrawableRegion region, GraphicsOptions options) { - } - - /// - /// Initializes a new instance of the class. - /// - /// The pen. - /// The path. - /// The options. - public DrawPathProcessor(IPen pen, IPath path, GraphicsOptions options) - : this(pen, new[] { path }, options) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The pen. - /// The paths. - /// The options. - public DrawPathProcessor(IPen pen, IEnumerable paths, GraphicsOptions options) - { - this.paths = paths.ToArray(); + this.region = region; this.pen = pen; this.options = options; - - if (this.paths.Length != 1) - { - var maxX = this.paths.Max(x => x.Bounds.Right); - var minX = this.paths.Min(x => x.Bounds.Left); - var maxY = this.paths.Max(x => x.Bounds.Bottom); - var minY = this.paths.Min(x => x.Bounds.Top); - - this.region = new RectangleF(minX, minY, maxX - minX, maxY - minY); - } - else - { - this.region = this.paths[0].Bounds.Convert(); - } } /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { using (PixelAccessor sourcePixels = source.Lock()) - using (PenApplicator applicator = this.pen.CreateApplicator(sourcePixels, this.region)) + using (PenApplicator applicator = this.pen.CreateApplicator(sourcePixels, this.region.Bounds)) { var rect = RectangleF.Ceiling(applicator.RequiredRegion); @@ -122,16 +85,14 @@ namespace ImageSharp.Drawing.Processors (int y) => { int offsetY = y - polyStartY; - var currentPoint = default(Vector2); + for (int x = minX; x < maxX; x++) { + // TODO add find intersections code to skip and scan large regions of this. int offsetX = x - startX; - currentPoint.X = offsetX; - currentPoint.Y = offsetY; + var info = this.region.GetPointInfo(offsetX, offsetY); - var dist = this.Closest(currentPoint); - - var color = applicator.GetColor(dist.Convert()); + var color = applicator.GetColor(offsetX, offsetY, info); var opacity = this.Opacity(color.DistanceFromElement); @@ -154,24 +115,6 @@ namespace ImageSharp.Drawing.Processors } } - private SixLabors.Shapes.PointInfo Closest(Vector2 point) - { - SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); - float distance = float.MaxValue; - - for (int i = 0; i < this.paths.Length; i++) - { - var p = this.paths[i].Distance(point); - if (p.DistanceFromPath < distance) - { - distance = p.DistanceFromPath; - result = p; - } - } - - return result; - } - private float Opacity(float distance) { if (distance <= 0) diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index dc87e6da6c..37bdac90f9 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -71,17 +71,12 @@ namespace ImageSharp.Drawing.Processors y => { int offsetY = y - startY; - - Vector2 currentPoint = default(Vector2); for (int x = minX; x < maxX; x++) { int offsetX = x - startX; - int offsetColorX = x - minX; - currentPoint.X = offsetX; - currentPoint.Y = offsetY; Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4(); - Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4(); + Vector4 sourceVector = applicator[offsetX, offsetY].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, 1); diff --git a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs b/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs index 14e99cba37..bdec022d49 100644 --- a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs @@ -25,18 +25,18 @@ namespace ImageSharp.Drawing.Processors private const float AntialiasFactor = 1f; private const int DrawPadding = 1; private readonly IBrush fillColor; - private readonly IShape poly; + private readonly IRegion region; private readonly GraphicsOptions options; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The brush. - /// The shape. + /// The region. /// The options. - public FillShapeProcessor(IBrush brush, IShape shape, GraphicsOptions options) + public FillShapeProcessor(IBrush brush, IRegion region, GraphicsOptions options) { - this.poly = shape; + this.region = region; this.fillColor = brush; this.options = options; } @@ -44,12 +44,12 @@ namespace ImageSharp.Drawing.Processors /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - Rectangle rect = RectangleF.Ceiling(this.poly.Bounds.Convert()); // rounds the points out away from the center + Rectangle rect = RectangleF.Ceiling(this.region.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 polyStartY = sourceRectangle.Y - DrawPadding; + int polyEndY = sourceRectangle.Bottom + DrawPadding; + int startX = sourceRectangle.X - DrawPadding; + int endX = sourceRectangle.Right + DrawPadding; int minX = Math.Max(sourceRectangle.Left, startX); int maxX = Math.Min(sourceRectangle.Right - 1, endX); @@ -62,9 +62,9 @@ namespace ImageSharp.Drawing.Processors minY = Math.Max(0, minY); maxY = Math.Min(source.Height, maxY); - ArrayPool arrayPool = ArrayPool.Shared; + ArrayPool arrayPool = ArrayPool.Shared; - int maxIntersections = this.poly.MaxIntersections; + int maxIntersections = this.region.MaxIntersections; using (PixelAccessor sourcePixels = source.Lock()) using (BrushApplicator applicator = this.fillColor.CreateApplicator(sourcePixels, rect)) @@ -73,27 +73,26 @@ namespace ImageSharp.Drawing.Processors minY, maxY, this.ParallelOptions, - y => + (int y) => { - Vector2[] buffer = arrayPool.Rent(maxIntersections); + float[] buffer = arrayPool.Rent(maxIntersections); try { - Vector2 left = new Vector2(startX, y); - Vector2 right = new Vector2(endX, y); + float right = endX; // foreach line we get all the points where this line crosses the polygon - int pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0); + int pointsFound = this.region.ScanY(y, buffer, maxIntersections, 0); if (pointsFound == 0) { // nothign on this line skip return; } - QuickSortX(buffer, pointsFound); + QuickSort(buffer, pointsFound); int currentIntersection = 0; - float nextPoint = buffer[0].X; + float nextPoint = buffer[0]; float lastPoint = float.MinValue; bool isInside = false; @@ -108,7 +107,7 @@ namespace ImageSharp.Drawing.Processors { if (x < (nextPoint - DrawPadding) && x > (lastPoint + DrawPadding)) { - if (nextPoint == right.X) + if (nextPoint == right) { // we are in the ends run skip it x = maxX; @@ -129,11 +128,11 @@ namespace ImageSharp.Drawing.Processors lastPoint = nextPoint; if (currentIntersection == pointsFound) { - nextPoint = right.X; + nextPoint = right; } else { - nextPoint = buffer[currentIntersection].X; + nextPoint = buffer[currentIntersection]; // double point from a corner flip the bit back and move on again if (nextPoint == lastPoint) @@ -143,11 +142,11 @@ namespace ImageSharp.Drawing.Processors currentIntersection++; if (currentIntersection == pointsFound) { - nextPoint = right.X; + nextPoint = right; } else { - nextPoint = buffer[currentIntersection].X; + nextPoint = buffer[currentIntersection]; } } } @@ -192,7 +191,7 @@ namespace ImageSharp.Drawing.Processors if (opacity > Constants.Epsilon) { Vector4 backgroundVector = sourcePixels[x, y].ToVector4(); - Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4(); + Vector4 sourceVector = applicator[x, y].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); finalColor.W = backgroundVector.W; @@ -216,42 +215,37 @@ namespace ImageSharp.Drawing.Processors minX, maxX, this.ParallelOptions, - x => + (int x) => { - Vector2[] buffer = arrayPool.Rent(maxIntersections); + float[] buffer = arrayPool.Rent(maxIntersections); try { - Vector2 left = new Vector2(x, polyStartY); - Vector2 right = new Vector2(x, polyEndY); + float left = polyStartY; + float right = polyEndY; // foreach line we get all the points where this line crosses the polygon - int pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0); + int pointsFound = this.region.ScanX(x, buffer, maxIntersections, 0); if (pointsFound == 0) { // nothign on this line skip return; } - QuickSortY(buffer, pointsFound); + QuickSort(buffer, pointsFound); int currentIntersection = 0; - float nextPoint = buffer[0].Y; - float lastPoint = left.Y; + float nextPoint = buffer[0]; + float lastPoint = left; 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) + if (nextPoint == right) { // we are in the ends run skip it y = maxY; @@ -266,7 +260,7 @@ namespace ImageSharp.Drawing.Processors { if (y < nextPoint - DrawPadding) { - if (nextPoint == right.Y) + if (nextPoint == right) { // we are in the ends run skip it y = maxY; @@ -286,11 +280,11 @@ namespace ImageSharp.Drawing.Processors lastPoint = nextPoint; if (currentIntersection == pointsFound) { - nextPoint = right.Y; + nextPoint = right; } else { - nextPoint = buffer[currentIntersection].Y; + nextPoint = buffer[currentIntersection]; // double point from a corner flip the bit back and move on again if (nextPoint == lastPoint) @@ -300,11 +294,11 @@ namespace ImageSharp.Drawing.Processors currentIntersection++; if (currentIntersection == pointsFound) { - nextPoint = right.Y; + nextPoint = right; } else { - nextPoint = buffer[currentIntersection].Y; + nextPoint = buffer[currentIntersection]; } } } @@ -350,8 +344,7 @@ namespace ImageSharp.Drawing.Processors if (opacity > Constants.Epsilon && opacity < 1) { Vector4 backgroundVector = sourcePixels[x, y].ToVector4(); - Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4(); - + Vector4 sourceVector = applicator[x, y].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); finalColor.W = backgroundVector.W; @@ -370,76 +363,32 @@ namespace ImageSharp.Drawing.Processors } } - private static void Swap(Vector2[] data, int left, int right) + private static void Swap(float[] data, int left, int right) { - Vector2 tmp = data[left]; + float tmp = data[left]; data[left] = data[right]; data[right] = tmp; } - private static void QuickSortY(Vector2[] data, int size) - { - int hi = Math.Min(data.Length - 1, size - 1); - QuickSortY(data, 0, hi); - } - - private static void QuickSortY(Vector2[] data, int lo, int hi) - { - if (lo < hi) - { - int p = PartitionY(data, lo, hi); - QuickSortY(data, lo, p); - QuickSortY(data, p + 1, hi); - } - } - - private static void QuickSortX(Vector2[] data, int size) + private static void QuickSort(float[] data, int size) { int hi = Math.Min(data.Length - 1, size - 1); - QuickSortX(data, 0, hi); + QuickSort(data, 0, hi); } - private static void QuickSortX(Vector2[] data, int lo, int hi) + private static void QuickSort(float[] data, int lo, int hi) { if (lo < hi) { - int p = PartitionX(data, lo, hi); - QuickSortX(data, lo, p); - QuickSortX(data, p + 1, hi); - } - } - - private static int PartitionX(Vector2[] data, int lo, int hi) - { - float pivot = data[lo].X; - int i = lo - 1; - int j = hi + 1; - while (true) - { - do - { - i = i + 1; - } - while (data[i].X < pivot && i < hi); - - do - { - j = j - 1; - } - while (data[j].X > pivot && j > lo); - - if (i >= j) - { - return j; - } - - Swap(data, i, j); + int p = Partition(data, lo, hi); + QuickSort(data, lo, p); + QuickSort(data, p + 1, hi); } } - private static int PartitionY(Vector2[] data, int lo, int hi) + private static int Partition(float[] data, int lo, int hi) { - float pivot = data[lo].Y; + float pivot = data[lo]; int i = lo - 1; int j = hi + 1; while (true) @@ -448,13 +397,13 @@ namespace ImageSharp.Drawing.Processors { i = i + 1; } - while (data[i].Y < pivot && i < hi); + while (data[i] < pivot && i < hi); do { j = j - 1; } - while (data[j].Y > pivot && j > lo); + while (data[j] > pivot && j > lo); if (i >= j) { diff --git a/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs b/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs index 939a718450..6613d15acb 100644 --- a/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs +++ b/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs @@ -12,6 +12,8 @@ namespace ImageSharp.Drawing.Processors using Drawing; using ImageSharp.Processing; using SixLabors.Shapes; + + using PointInfo = ImageSharp.Drawing.PointInfo; using Rectangle = ImageSharp.Rectangle; /// @@ -29,8 +31,7 @@ namespace ImageSharp.Drawing.Processors return new PointInfo { DistanceAlongPath = source.DistanceAlongPath, - DistanceFromPath = source.DistanceFromPath, - SearchPoint = source.SearchPoint + DistanceFromPath = source.DistanceFromPath }; } } diff --git a/src/ImageSharp.Drawing/ShapeRegion.cs b/src/ImageSharp.Drawing/ShapeRegion.cs new file mode 100644 index 0000000000..6bd0703672 --- /dev/null +++ b/src/ImageSharp.Drawing/ShapeRegion.cs @@ -0,0 +1,180 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + using System.Buffers; + using System.Collections.Immutable; + using System.Numerics; + + using ImageSharp.Drawing.Processors; + + using SixLabors.Shapes; + + using Rectangle = ImageSharp.Rectangle; + + /// + /// A drawable mapping between a / and a drawable/fillable region. + /// + /// + internal class ShapeRegion : IDrawableRegion + { + /// + /// The fillable shape + /// + private readonly IShape shape; + + /// + /// The drawable paths + /// + private readonly ImmutableArray paths; + + /// + /// Initializes a new instance of the class. + /// + /// The path. + public ShapeRegion(IPath path) + : this(ImmutableArray.Create(path)) + { + this.shape = path.AsShape(); + this.Bounds = RectangleF.Ceiling(path.Bounds.Convert()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The shape. + public ShapeRegion(IShape shape) + : this(shape.Paths) + { + this.shape = shape; + this.Bounds = RectangleF.Ceiling(shape.Bounds.Convert()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The paths. + private ShapeRegion(ImmutableArray paths) + { + this.paths = paths; + } + + /// + /// Gets the maximum number of intersections to could be returned. + /// + /// + /// The maximum intersections. + /// + public int MaxIntersections => this.shape.MaxIntersections; + + /// + /// Gets the bounds. + /// + /// + /// The bounds. + /// + public Rectangle Bounds { get; } + + /// + /// Scans the X axis for intersections. + /// + /// The x. + /// The buffer. + /// The length. + /// The offset. + /// + /// The number of intersections found. + /// + public int ScanX(int x, float[] buffer, int length, int offset) + { + var start = new Vector2(x, this.Bounds.Top - 1); + var end = new Vector2(x, this.Bounds.Bottom + 1); + Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); + try + { + int count = this.shape.FindIntersections( + start, + end, + innerbuffer, + length, + 0); + + for (var i = 0; i < count; i++) + { + buffer[i + offset] = innerbuffer[i].Y; + } + + return count; + } + finally + { + ArrayPool.Shared.Return(innerbuffer); + } + } + + /// + /// Scans the Y axis for intersections. + /// + /// The position along the y axis to find intersections. + /// The buffer. + /// The length. + /// The offset. + /// + /// The number of intersections found. + /// + public int ScanY(int y, float[] buffer, int length, int offset) + { + var start = new Vector2(this.Bounds.Left - 1, y); + var end = new Vector2(this.Bounds.Right + 1, y); + Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); + try + { + int count = this.shape.FindIntersections( + start, + end, + innerbuffer, + length, + 0); + + for (var i = 0; i < count; i++) + { + buffer[i + offset] = innerbuffer[i].X; + } + + return count; + } + finally + { + ArrayPool.Shared.Return(innerbuffer); + } + } + + /// + /// Gets the point information for the specified x and y location. + /// + /// The x. + /// The y. + /// Information about the the point + public PointInfo GetPointInfo(int x, int y) + { + var point = new Vector2(x, y); + SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); + float distance = float.MaxValue; + + for (int i = 0; i < this.paths.Length; i++) + { + var p = this.paths[i].Distance(point); + if (p.DistanceFromPath < distance) + { + distance = p.DistanceFromPath; + result = p; + } + } + + return result.Convert(); + } + } +} diff --git a/src/ImageSharp.Drawing/project.json b/src/ImageSharp.Drawing/project.json index f0d4c62432..5fcee9b41e 100644 --- a/src/ImageSharp.Drawing/project.json +++ b/src/ImageSharp.Drawing/project.json @@ -39,14 +39,12 @@ }, "dependencies": { "ImageSharp": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, - "SixLabors.Shapes": "0.1.0-ci0043", + "SixLabors.Shapes": "0.1.0-ci0047", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 305fac6369..75212d3617 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -179,6 +179,9 @@ ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\ImageSharp.Drawing.dll + + ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\SixLabors.Shapes.dll + ..\..\src\ImageSharp.Formats.Bmp\bin\$(Configuration)\net461\ImageSharp.Formats.Bmp.dll diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index b619483162..31aa87d4b7 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -7,12 +7,13 @@ namespace ImageSharp.Tests.Drawing { using Drawing; using ImageSharp.Drawing; - using CorePath = ImageSharp.Drawing.Paths.Path; - using ImageSharp.Drawing.Paths; + using CorePath = SixLabors.Shapes.Path; + using SixLabors.Shapes; using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Numerics; + using Xunit; public class DrawPathTests : FileTestBase diff --git a/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs b/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs new file mode 100644 index 0000000000..070e555016 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs @@ -0,0 +1,71 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace SixLabors.Shapes +{ + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Numerics; + + using SixLabors.Shapes; + public class BezierPolygon : IShape + { + private Polygon polygon; + + public BezierPolygon(params Vector2[] points) + { + this.polygon = new Polygon(new BezierLineSegment(points)); + } + + public float Distance(Vector2 point) + { + return this.polygon.Distance(point); + } + + public bool Contains(Vector2 point) + { + return this.polygon.Contains(point); + } + + public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) + { + return this.polygon.FindIntersections(start, end, buffer, count, offset); + } + + public IEnumerable FindIntersections(Vector2 start, Vector2 end) + { + return this.polygon.FindIntersections(start, end); + } + + public IShape Transform(Matrix3x2 matrix) + { + return ((IShape)this.polygon).Transform(matrix); + } + + public Rectangle Bounds + { + get + { + return this.polygon.Bounds; + } + } + + public ImmutableArray Paths + { + get + { + return this.polygon.Paths; + } + } + + public int MaxIntersections + { + get + { + return this.polygon.MaxIntersections; + } + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs b/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs new file mode 100644 index 0000000000..fa94882665 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs @@ -0,0 +1,71 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace SixLabors.Shapes +{ + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Numerics; + + using SixLabors.Shapes; + public class LinearPolygon : IShape + { + private Polygon polygon; + + public LinearPolygon(params Vector2[] points) + { + this.polygon = new Polygon(new LinearLineSegment(points)); + } + + public float Distance(Vector2 point) + { + return this.polygon.Distance(point); + } + + public bool Contains(Vector2 point) + { + return this.polygon.Contains(point); + } + + public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) + { + return this.polygon.FindIntersections(start, end, buffer, count, offset); + } + + public IEnumerable FindIntersections(Vector2 start, Vector2 end) + { + return this.polygon.FindIntersections(start, end); + } + + public IShape Transform(Matrix3x2 matrix) + { + return ((IShape)this.polygon).Transform(matrix); + } + + public Rectangle Bounds + { + get + { + return this.polygon.Bounds; + } + } + + public ImmutableArray Paths + { + get + { + return this.polygon.Paths; + } + } + + public int MaxIntersections + { + get + { + return this.polygon.MaxIntersections; + } + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index 9ce93ee899..dd2ea5249c 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -7,26 +7,29 @@ namespace ImageSharp.Tests.Drawing { using System.IO; using Xunit; - + using Drawing; + using ImageSharp.Drawing; using System.Numerics; - using ImageSharp.Drawing.Shapes; using ImageSharp.Drawing.Pens; + using SixLabors.Shapes; + public class LineComplexPolygonTests : FileTestBase { [Fact] public void ImageShouldBeOverlayedByPolygonOutline() { string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + + var simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + var hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(93, 85), - new Vector2(65, 137)); + new Vector2(65, 137))); using (Image image = new Image(500, 500)) { @@ -34,8 +37,8 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1)) - .Save(output); + .DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1)) + .Save(output); } using (PixelAccessor sourcePixels = image.Lock()) @@ -128,6 +131,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(37, 85), new Vector2(130, 40), new Vector2(65, 137)); + var clipped = simplePath.Clip(hole1); using (Image image = new Image(500, 500)) { @@ -135,7 +139,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1)) + .DrawPolygon(Color.HotPink, 5, clipped) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 18275ef385..82e4ac33e2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -9,6 +9,9 @@ namespace ImageSharp.Tests.Drawing using System.IO; using System.Numerics; + + using SixLabors.Shapes; + using Xunit; public class SolidBezierTests : FileTestBase diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index 144a1398d8..a1973a280b 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -7,9 +7,11 @@ namespace ImageSharp.Tests.Drawing { using System.IO; using Xunit; - + using Drawing; + using ImageSharp.Drawing; using System.Numerics; - using ImageSharp.Drawing.Shapes; + + using SixLabors.Shapes; public class SolidComplexPolygonTests : FileTestBase { @@ -33,7 +35,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1)) + .Fill(Color.HotPink, simplePath.Clip(hole1)) .Save(output); } @@ -76,7 +78,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, new ComplexPolygon(simplePath, hole1)) + .Fill(Color.HotPink, simplePath.Clip(hole1)) .Save(output); } @@ -119,8 +121,8 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(color, new ComplexPolygon(simplePath, hole1)) - .Save(output); + .Fill(color, simplePath.Clip(hole1)) + .Save(output); } //shift background color towards forground color by the opacity amount @@ -144,4 +146,4 @@ namespace ImageSharp.Tests.Drawing } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index b4cf8e0905..3e20b3a09a 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -5,8 +5,10 @@ namespace ImageSharp.Tests.Drawing { + using Drawing; using ImageSharp.Drawing; - + using System; + using System.Diagnostics.CodeAnalysis; using System.IO; using System.Numerics; using Xunit; @@ -142,14 +144,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledRectangle() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); + using (Image image = new Image(500, 500)) { using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new Rectangle(10, 10, 190, 140))) - .Save(output); + .Fill(Color.HotPink, new SixLabors.Shapes.Rectangle(10,10, 190, 140)) + .Save(output); } using (PixelAccessor sourcePixels = image.Lock()) From 7fbc7559079bd767f25b822b361a1811c0d3d477 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 31 Jan 2017 22:12:26 +0000 Subject: [PATCH 03/19] split out paths from basic drawing --- ImageSharp.sln | 8 + src/ImageSharp.Drawing.Paths/DrawBeziers.cs | 120 +++++ src/ImageSharp.Drawing.Paths/DrawLines.cs | 120 +++++ src/ImageSharp.Drawing.Paths/DrawPath.cs | 124 +++++ src/ImageSharp.Drawing.Paths/DrawPolygon.cs | 104 ++++ .../DrawRectangle.cs | 24 +- src/ImageSharp.Drawing.Paths/DrawShape.cs | 118 ++++ src/ImageSharp.Drawing.Paths/FillPaths.cs | 87 +++ src/ImageSharp.Drawing.Paths/FillPolygon.cs | 83 +++ .../FillRectangle.cs | 8 +- src/ImageSharp.Drawing.Paths/FillShapes.cs | 83 +++ .../ImageSharp.Drawing.Paths.xproj | 25 + .../PointInfoExtensions.cs | 21 +- .../Properties/AssemblyInfo.cs | 6 + .../RectangleExtensions.cs | 12 +- .../ShapePath.cs} | 31 +- src/ImageSharp.Drawing.Paths/ShapeRegion.cs | 137 +++++ src/ImageSharp.Drawing.Paths/project.json | 96 ++++ .../Brushes/Processors/BrushApplicator.cs | 1 - src/ImageSharp.Drawing/Draw.cs | 506 ------------------ src/ImageSharp.Drawing/DrawPath.cs | 123 +++++ src/ImageSharp.Drawing/Fill.cs | 173 ------ src/ImageSharp.Drawing/FillRegion.cs | 111 ++++ src/ImageSharp.Drawing/IDrawableRegion.cs | 24 - src/ImageSharp.Drawing/Path.cs | 57 ++ .../Processors/DrawPathProcessor.cs | 5 +- ...apeProcessor.cs => FillRegionProcessor.cs} | 29 +- .../{IRegion.cs => Region.cs} | 14 +- src/ImageSharp.Drawing/project.json | 1 - .../Drawing/FillRectangle.cs | 2 +- tests/ImageSharp.Benchmarks/project.json | 24 +- .../ImageSharp.Sandbox46.csproj | 5 +- .../ImageSharp.Tests/Drawing/DrawPathTests.cs | 10 +- .../Drawing/LineComplexPolygonTests.cs | 12 +- .../ImageSharp.Tests/Drawing/PolygonTests.cs | 2 +- .../Drawing/SolidPolygonTests.cs | 2 +- tests/ImageSharp.Tests/project.json | 24 +- 37 files changed, 1509 insertions(+), 823 deletions(-) create mode 100644 src/ImageSharp.Drawing.Paths/DrawBeziers.cs create mode 100644 src/ImageSharp.Drawing.Paths/DrawLines.cs create mode 100644 src/ImageSharp.Drawing.Paths/DrawPath.cs create mode 100644 src/ImageSharp.Drawing.Paths/DrawPolygon.cs rename src/{ImageSharp.Drawing => ImageSharp.Drawing.Paths}/DrawRectangle.cs (73%) create mode 100644 src/ImageSharp.Drawing.Paths/DrawShape.cs create mode 100644 src/ImageSharp.Drawing.Paths/FillPaths.cs create mode 100644 src/ImageSharp.Drawing.Paths/FillPolygon.cs rename src/{ImageSharp.Drawing => ImageSharp.Drawing.Paths}/FillRectangle.cs (93%) create mode 100644 src/ImageSharp.Drawing.Paths/FillShapes.cs create mode 100644 src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.xproj rename src/{ImageSharp.Drawing/Processors => ImageSharp.Drawing.Paths}/PointInfoExtensions.cs (62%) create mode 100644 src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs rename src/{ImageSharp.Drawing/Processors => ImageSharp.Drawing.Paths}/RectangleExtensions.cs (58%) rename src/{ImageSharp.Drawing/ShapeRegion.cs => ImageSharp.Drawing.Paths/ShapePath.cs} (83%) create mode 100644 src/ImageSharp.Drawing.Paths/ShapeRegion.cs create mode 100644 src/ImageSharp.Drawing.Paths/project.json delete mode 100644 src/ImageSharp.Drawing/Draw.cs create mode 100644 src/ImageSharp.Drawing/DrawPath.cs delete mode 100644 src/ImageSharp.Drawing/Fill.cs create mode 100644 src/ImageSharp.Drawing/FillRegion.cs delete mode 100644 src/ImageSharp.Drawing/IDrawableRegion.cs create mode 100644 src/ImageSharp.Drawing/Path.cs rename src/ImageSharp.Drawing/Processors/{FillShapeProcessor.cs => FillRegionProcessor.cs} (95%) rename src/ImageSharp.Drawing/{IRegion.cs => Region.cs} (78%) diff --git a/ImageSharp.sln b/ImageSharp.sln index f1e9fb1045..503a5b8601 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -60,11 +60,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} = {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} {7213767C-0003-41CA-AB18-0223CFA7CE4B} = {7213767C-0003-41CA-AB18-0223CFA7CE4B} + {E5BD4F96-28A8-410C-8B63-1C5731948549} = {E5BD4F96-28A8-410C-8B63-1C5731948549} {C77661B9-F793-422E-8E27-AC60ECC5F215} = {C77661B9-F793-422E-8E27-AC60ECC5F215} {556ABDCF-ED93-4327-BE98-F6815F78B9B8} = {556ABDCF-ED93-4327-BE98-F6815F78B9B8} {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {A623CFE9-9D2B-4528-AD1F-2E834B061134} EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing.Paths", "src\ImageSharp.Drawing.Paths\ImageSharp.Drawing.Paths.xproj", "{E5BD4F96-28A8-410C-8B63-1C5731948549}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -115,6 +118,10 @@ Global {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.Build.0 = Release|Any CPU + {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -132,5 +139,6 @@ Global {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {9E574A07-F879-4811-9C41-5CBDC6BAFDB7} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {E5BD4F96-28A8-410C-8B63-1C5731948549} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} EndGlobalSection EndGlobal diff --git a/src/ImageSharp.Drawing.Paths/DrawBeziers.cs b/src/ImageSharp.Drawing.Paths/DrawBeziers.cs new file mode 100644 index 0000000000..6515db5771 --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/DrawBeziers.cs @@ -0,0 +1,120 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + using SixLabors.Shapes; + + using Path = SixLabors.Shapes.Path; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Path(new BezierLineSegment(points)), options); + } + + /// + /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The Image + public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Path(new BezierLineSegment(points))); + } + + /// + /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The Image + public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawBeziers(new SolidBrush(color), thickness, points); + } + + /// + /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawBeziers(new SolidBrush(color), thickness, points, options); + } + + /// + /// Draws the provided Points as an open Bezier path with the supplied pen + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Path(new BezierLineSegment(points)), options); + } + + /// + /// Draws the provided Points as an open Bezier path with the supplied pen + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// The Image + public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Path(new BezierLineSegment(points))); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/DrawLines.cs b/src/ImageSharp.Drawing.Paths/DrawLines.cs new file mode 100644 index 0000000000..2e4f849870 --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/DrawLines.cs @@ -0,0 +1,120 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + using SixLabors.Shapes; + + using Path = SixLabors.Shapes.Path; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Path(new LinearLineSegment(points)), options); + } + + /// + /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The Image + public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Path(new LinearLineSegment(points))); + } + + /// + /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The Image + public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawLines(new SolidBrush(color), thickness, points); + } + + /// + /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawLines(new SolidBrush(color), thickness, points, options); + } + + /// + /// Draws the provided Points as an open Linear path with the supplied pen + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawLines(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Path(new LinearLineSegment(points)), options); + } + + /// + /// Draws the provided Points as an open Linear path with the supplied pen + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// The Image + public static Image DrawLines(this Image source, IPen pen, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Path(new LinearLineSegment(points))); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/DrawPath.cs b/src/ImageSharp.Drawing.Paths/DrawPath.cs new file mode 100644 index 0000000000..201984e0ac --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/DrawPath.cs @@ -0,0 +1,124 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the outline of the polygon with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IPen pen, IPath path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new ShapePath(path), options); + } + + /// + /// Draws the outline of the polygon with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, IPen pen, IPath path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, path, GraphicsOptions.Default); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The shape. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IBrush brush, float thickness, IPath path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), path, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, IBrush brush, float thickness, IPath path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), path); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, TColor color, float thickness, IPath path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, path, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, TColor color, float thickness, IPath path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, path); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs new file mode 100644 index 0000000000..73d8ec0e7f --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs @@ -0,0 +1,104 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points)), options); + } + + /// + /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The points. + /// The Image + public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points))); + } + + /// + /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The Image + public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawPolygon(new SolidBrush(color), thickness, points); + } + + /// + /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.DrawPolygon(new SolidBrush(color), thickness, points, options); + } + + /// + /// Draws the provided Points as a closed Linear Polygon with the provided Pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Polygon(new LinearLineSegment(points)), options); + } + } +} diff --git a/src/ImageSharp.Drawing/DrawRectangle.cs b/src/ImageSharp.Drawing.Paths/DrawRectangle.cs similarity index 73% rename from src/ImageSharp.Drawing/DrawRectangle.cs rename to src/ImageSharp.Drawing.Paths/DrawRectangle.cs index 243aa082d4..28ea3d6e03 100644 --- a/src/ImageSharp.Drawing/DrawRectangle.cs +++ b/src/ImageSharp.Drawing.Paths/DrawRectangle.cs @@ -30,10 +30,10 @@ namespace ImageSharp /// /// The Image /// - public static Image DrawPolygon(this Image source, IPen pen, RectangleF shape, GraphicsOptions options) + public static Image Draw(this Image source, IPen pen, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height)), options)); + return source.Draw(pen, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options); } /// @@ -44,10 +44,10 @@ namespace ImageSharp /// The pen. /// The shape. /// The Image - public static Image DrawPolygon(this Image source, IPen pen, RectangleF shape) + public static Image Draw(this Image source, IPen pen, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { - return source.DrawPolygon(pen, shape, GraphicsOptions.Default); + return source.Draw(pen, shape, GraphicsOptions.Default); } /// @@ -62,10 +62,10 @@ namespace ImageSharp /// /// The Image /// - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, RectangleF shape, GraphicsOptions options) + public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.DrawPolygon(new Pen(brush, thickness), shape, options); + return source.Draw(new Pen(brush, thickness), shape, options); } /// @@ -77,10 +77,10 @@ namespace ImageSharp /// The thickness. /// The shape. /// The Image - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, RectangleF shape) + public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { - return source.DrawPolygon(new Pen(brush, thickness), shape); + return source.Draw(new Pen(brush, thickness), shape); } /// @@ -95,10 +95,10 @@ namespace ImageSharp /// /// The Image /// - public static Image DrawPolygon(this Image source, TColor color, float thickness, RectangleF shape, GraphicsOptions options) + public static Image Draw(this Image source, TColor color, float thickness, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { - return source.DrawPolygon(new SolidBrush(color), thickness, shape, options); + return source.Draw(new SolidBrush(color), thickness, shape, options); } /// @@ -110,10 +110,10 @@ namespace ImageSharp /// The thickness. /// The shape. /// The Image - public static Image DrawPolygon(this Image source, TColor color, float thickness, RectangleF shape) + public static Image Draw(this Image source, TColor color, float thickness, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { - return source.DrawPolygon(new SolidBrush(color), thickness, shape); + return source.Draw(new SolidBrush(color), thickness, shape); } } } diff --git a/src/ImageSharp.Drawing.Paths/DrawShape.cs b/src/ImageSharp.Drawing.Paths/DrawShape.cs new file mode 100644 index 0000000000..15ae2b1797 --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/DrawShape.cs @@ -0,0 +1,118 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the outline of the polygon with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The shape. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IPen pen, IShape shape, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new ShapePath(shape), options); + } + + /// + /// Draws the outline of the polygon with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The shape. + /// The Image + public static Image Draw(this Image source, IPen pen, IShape shape) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, shape, GraphicsOptions.Default); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The shape. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IBrush brush, float thickness, IShape shape, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), shape, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The shape. + /// The Image + public static Image Draw(this Image source, IBrush brush, float thickness, IShape shape) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), shape); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The shape. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, TColor color, float thickness, IShape shape, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, shape, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The shape. + /// The Image + public static Image Draw(this Image source, TColor color, float thickness, IShape shape) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, shape); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/FillPaths.cs b/src/ImageSharp.Drawing.Paths/FillPaths.cs new file mode 100644 index 0000000000..3095ee7cdf --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/FillPaths.cs @@ -0,0 +1,87 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Processors; + + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The shape. + /// The graphics options. + /// + /// The Image + /// + public static Image Fill(this Image source, IBrush brush, IPath path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new ShapeRegion(path), options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The path. + /// + /// The Image + /// + public static Image Fill(this Image source, IBrush brush, IPath path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new ShapeRegion(path), GraphicsOptions.Default); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The color. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Fill(this Image source, TColor color, IPath path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), path, options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The color. + /// The path. + /// + /// The Image + /// + public static Image Fill(this Image source, TColor color, IPath path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), path); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/FillPolygon.cs b/src/ImageSharp.Drawing.Paths/FillPolygon.cs new file mode 100644 index 0000000000..4092e5fc64 --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/FillPolygon.cs @@ -0,0 +1,83 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Processors; + + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flood fills the image in the shape of a Linear polygon described by the points + /// + /// The type of the color. + /// The source. + /// The brush. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options); + } + + /// + /// Flood fills the image in the shape of a Linear polygon described by the points + /// + /// The type of the color. + /// The source. + /// The brush. + /// The points. + /// The Image + public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new Polygon(new LinearLineSegment(points))); + } + + /// + /// Flood fills the image in the shape of a Linear polygon described by the points + /// + /// The type of the color. + /// The source. + /// The color. + /// The points. + /// The options. + /// + /// The Image + /// + public static Image FillPolygon(this Image source, TColor color, Vector2[] points, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)), options); + } + + /// + /// Flood fills the image in the shape of a Linear polygon described by the points + /// + /// The type of the color. + /// The source. + /// The color. + /// The points. + /// The Image + public static Image FillPolygon(this Image source, TColor color, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points))); + } + } +} diff --git a/src/ImageSharp.Drawing/FillRectangle.cs b/src/ImageSharp.Drawing.Paths/FillRectangle.cs similarity index 93% rename from src/ImageSharp.Drawing/FillRectangle.cs rename to src/ImageSharp.Drawing.Paths/FillRectangle.cs index d60a5a19d8..aef777edd2 100644 --- a/src/ImageSharp.Drawing/FillRectangle.cs +++ b/src/ImageSharp.Drawing.Paths/FillRectangle.cs @@ -27,7 +27,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Fill(this Image source, IBrush brush, RectangleF shape, GraphicsOptions options) + public static Image Fill(this Image source, IBrush brush, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options); @@ -41,7 +41,7 @@ namespace ImageSharp /// The brush. /// The shape. /// The Image - public static Image Fill(this Image source, IBrush brush, RectangleF shape) + public static Image Fill(this Image source, IBrush brush, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height)); @@ -58,7 +58,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Fill(this Image source, TColor color, RectangleF shape, GraphicsOptions options) + public static Image Fill(this Image source, TColor color, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { return source.Fill(new SolidBrush(color), shape, options); @@ -72,7 +72,7 @@ namespace ImageSharp /// The color. /// The shape. /// The Image - public static Image Fill(this Image source, TColor color, RectangleF shape) + public static Image Fill(this Image source, TColor color, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { return source.Fill(new SolidBrush(color), shape); diff --git a/src/ImageSharp.Drawing.Paths/FillShapes.cs b/src/ImageSharp.Drawing.Paths/FillShapes.cs new file mode 100644 index 0000000000..9fe473ee1c --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/FillShapes.cs @@ -0,0 +1,83 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Processors; + + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The shape. + /// The graphics options. + /// + /// The Image + /// + public static Image Fill(this Image source, IBrush brush, IShape shape, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new ShapeRegion(shape), options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The shape. + /// The Image + public static Image Fill(this Image source, IBrush brush, IShape shape) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, new ShapeRegion(shape), GraphicsOptions.Default); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The color. + /// The shape. + /// The options. + /// + /// The Image + /// + public static Image Fill(this Image source, TColor color, IShape shape, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), shape, options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The source. + /// The color. + /// The shape. + /// The Image + public static Image Fill(this Image source, TColor color, IShape shape) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), shape); + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.xproj b/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.xproj new file mode 100644 index 0000000000..196f7bc1bc --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.xproj @@ -0,0 +1,25 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + e5bd4f96-28a8-410c-8b63-1c5731948549 + ImageSharp.Drawing + .\obj + .\bin\ + v4.5.1 + + + 2.0 + + + True + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs b/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs similarity index 62% rename from src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs rename to src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs index 6613d15acb..ea38dfb9d3 100644 --- a/src/ImageSharp.Drawing/Processors/PointInfoExtensions.cs +++ b/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs @@ -3,19 +3,8 @@ // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp.Drawing.Processors +namespace ImageSharp.Drawing { - using System; - using System.Buffers; - using System.Numerics; - using System.Threading.Tasks; - using Drawing; - using ImageSharp.Processing; - using SixLabors.Shapes; - - using PointInfo = ImageSharp.Drawing.PointInfo; - using Rectangle = ImageSharp.Rectangle; - /// /// Extension methods for helping to bridge Shaper2D and ImageSharp primitives. /// @@ -29,10 +18,10 @@ namespace ImageSharp.Drawing.Processors public static PointInfo Convert(this SixLabors.Shapes.PointInfo source) { return new PointInfo - { - DistanceAlongPath = source.DistanceAlongPath, - DistanceFromPath = source.DistanceFromPath - }; + { + DistanceAlongPath = source.DistanceAlongPath, + DistanceFromPath = source.DistanceFromPath + }; } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs b/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..fba25a9dba --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +// Common values read from `AssemblyInfo.Common.cs` diff --git a/src/ImageSharp.Drawing/Processors/RectangleExtensions.cs b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs similarity index 58% rename from src/ImageSharp.Drawing/Processors/RectangleExtensions.cs rename to src/ImageSharp.Drawing.Paths/RectangleExtensions.cs index 327b618fa4..05d6bb6ced 100644 --- a/src/ImageSharp.Drawing/Processors/RectangleExtensions.cs +++ b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs @@ -20,13 +20,17 @@ namespace ImageSharp.Drawing.Processors internal static class RectangleExtensions { /// - /// Converts a Shaper2D to an ImageSharp . + /// Converts a Shaper2D to an ImageSharp by creating a the entirely surrounds the source. /// /// The source. - /// A representation of this - public static RectangleF Convert(this SixLabors.Shapes.Rectangle source) + /// A representation of this + public static Rectangle Convert(this SixLabors.Shapes.Rectangle source) { - return new RectangleF(source.Location.X, source.Location.Y, source.Size.Width, source.Size.Height); + int y = (int)Math.Floor(source.Y); + int width = (int)Math.Ceiling(source.Size.Width); + int x = (int)Math.Floor(source.X); + int height = (int)Math.Ceiling(source.Size.Height); + return new Rectangle(x, y, width, height); } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs similarity index 83% rename from src/ImageSharp.Drawing/ShapeRegion.cs rename to src/ImageSharp.Drawing.Paths/ShapePath.cs index 6bd0703672..63d5fc9e1b 100644 --- a/src/ImageSharp.Drawing/ShapeRegion.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -18,8 +18,7 @@ namespace ImageSharp.Drawing /// /// A drawable mapping between a / and a drawable/fillable region. /// - /// - internal class ShapeRegion : IDrawableRegion + internal class ShapePath : ImageSharp.Drawing.Path { /// /// The fillable shape @@ -32,10 +31,10 @@ namespace ImageSharp.Drawing private readonly ImmutableArray paths; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The path. - public ShapeRegion(IPath path) + public ShapePath(IPath path) : this(ImmutableArray.Create(path)) { this.shape = path.AsShape(); @@ -43,10 +42,10 @@ namespace ImageSharp.Drawing } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The shape. - public ShapeRegion(IShape shape) + public ShapePath(IShape shape) : this(shape.Paths) { this.shape = shape; @@ -54,10 +53,10 @@ namespace ImageSharp.Drawing } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The paths. - private ShapeRegion(ImmutableArray paths) + private ShapePath(ImmutableArray paths) { this.paths = paths; } @@ -68,7 +67,7 @@ namespace ImageSharp.Drawing /// /// The maximum intersections. /// - public int MaxIntersections => this.shape.MaxIntersections; + public override int MaxIntersections => this.shape.MaxIntersections; /// /// Gets the bounds. @@ -76,7 +75,7 @@ namespace ImageSharp.Drawing /// /// The bounds. /// - public Rectangle Bounds { get; } + public override Rectangle Bounds { get; } /// /// Scans the X axis for intersections. @@ -88,7 +87,7 @@ namespace ImageSharp.Drawing /// /// The number of intersections found. /// - public int ScanX(int x, float[] buffer, int length, int offset) + public override int ScanX(int x, float[] buffer, int length, int offset) { var start = new Vector2(x, this.Bounds.Top - 1); var end = new Vector2(x, this.Bounds.Bottom + 1); @@ -125,10 +124,10 @@ namespace ImageSharp.Drawing /// /// The number of intersections found. /// - public int ScanY(int y, float[] buffer, int length, int offset) + public override int ScanY(int y, float[] buffer, int length, int offset) { - var start = new Vector2(this.Bounds.Left - 1, y); - var end = new Vector2(this.Bounds.Right + 1, y); + var start = new Vector2(float.MinValue, y); + var end = new Vector2(float.MaxValue, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { @@ -158,7 +157,7 @@ namespace ImageSharp.Drawing /// The x. /// The y. /// Information about the the point - public PointInfo GetPointInfo(int x, int y) + public override PointInfo GetPointInfo(int x, int y) { var point = new Vector2(x, y); SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs new file mode 100644 index 0000000000..d1a59a99d9 --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs @@ -0,0 +1,137 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + using System.Buffers; + using System.Collections.Immutable; + using System.Numerics; + + using ImageSharp.Drawing.Processors; + + using SixLabors.Shapes; + + using Rectangle = ImageSharp.Rectangle; + + /// + /// A drawable mapping between a / and a drawable/fillable region. + /// + internal class ShapeRegion : Region + { + /// + /// The fillable shape + /// + private readonly IShape shape; + + /// + /// Initializes a new instance of the class. + /// + /// The path. + public ShapeRegion(IPath path) + : this(path.AsShape()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The shape. + public ShapeRegion(IShape shape) + { + this.shape = shape; + this.Bounds = shape.Bounds.Convert(); + } + + /// + /// Gets the maximum number of intersections to could be returned. + /// + /// + /// The maximum intersections. + /// + public override int MaxIntersections => this.shape.MaxIntersections; + + /// + /// Gets the bounds. + /// + /// + /// The bounds. + /// + public override Rectangle Bounds { get; } + + /// + /// Scans the X axis for intersections. + /// + /// The x. + /// The buffer. + /// The length. + /// The offset. + /// + /// The number of intersections found. + /// + public override int ScanX(int x, float[] buffer, int length, int offset) + { + var start = new Vector2(x, this.Bounds.Top - 1); + var end = new Vector2(x, this.Bounds.Bottom + 1); + Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); + try + { + int count = this.shape.FindIntersections( + start, + end, + innerbuffer, + length, + 0); + + for (var i = 0; i < count; i++) + { + buffer[i + offset] = innerbuffer[i].Y; + } + + return count; + } + finally + { + ArrayPool.Shared.Return(innerbuffer); + } + } + + /// + /// Scans the Y axis for intersections. + /// + /// The position along the y axis to find intersections. + /// The buffer. + /// The length. + /// The offset. + /// + /// The number of intersections found. + /// + public override int ScanY(int y, float[] buffer, int length, int offset) + { + var start = new Vector2(float.MinValue, y); + var end = new Vector2(float.MaxValue, y); + Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); + try + { + int count = this.shape.FindIntersections( + start, + end, + innerbuffer, + length, + 0); + + for (var i = 0; i < count; i++) + { + buffer[i + offset] = innerbuffer[i].X; + } + + return count; + } + finally + { + ArrayPool.Shared.Return(innerbuffer); + } + } + } +} diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json new file mode 100644 index 0000000000..cdc5d2244f --- /dev/null +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -0,0 +1,96 @@ +{ + "version": "1.0.0-alpha1-*", + "title": "ImageSharp.Drawing.Paths", + "description": "A cross-platform library for the processing of image files; written in C#", + "authors": [ + "James Jackson-South and contributors" + ], + "packOptions": { + "owners": [ + "James Jackson-South and contributors" + ], + "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", + "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", + "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", + "requireLicenseAcceptance": false, + "repository": { + "type": "git", + "url": "https://github.com/JimBobSquarePants/ImageSharp" + }, + "tags": [ + "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" + ] + }, + "buildOptions": { + "allowUnsafe": true, + "xmlDoc": true, + "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], + "compile": [ + "../Shared/*.cs" + ] + }, + "configurations": { + "Release": { + "buildOptions": { + "warningsAsErrors": true, + "optimize": true + } + } + }, + "dependencies": { + "ImageSharp": { + "target": "project" + }, + "ImageSharp.Drawing": { + "target": "project" + }, + "SixLabors.Shapes": "0.1.0-ci0050", + "StyleCop.Analyzers": { + "version": "1.0.0", + "type": "build" + }, + "System.Buffers": "4.0.0", + "System.Runtime.CompilerServices.Unsafe": "4.0.0" + }, + "frameworks": { + "netstandard1.1": { + "dependencies": { + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Diagnostics.Tools": "4.0.1", + "System.IO": "4.1.0", + "System.IO.Compression": "4.1.0", + "System.Linq": "4.1.0", + "System.Numerics.Vectors": "4.1.1", + "System.ObjectModel": "4.0.12", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime.Extensions": "4.1.0", + "System.Runtime.InteropServices": "4.1.0", + "System.Runtime.Numerics": "4.0.1", + "System.Text.Encoding.Extensions": "4.0.11", + "System.Threading": "4.0.11", + "System.Threading.Tasks": "4.0.11", + "System.Threading.Tasks.Parallel": "4.0.1" + } + }, + "net45": { + "dependencies": { + "System.Numerics.Vectors": "4.1.1", + "System.Threading.Tasks.Parallel": "4.0.0" + }, + "frameworkAssemblies": { + "System.Runtime": { "type": "build" } + } + }, + "net461": { + "dependencies": { + "System.Threading.Tasks.Parallel": "4.0.0" + }, + "frameworkAssemblies": { + "System.Runtime": { "type": "build" }, + "System.Numerics": "4.0.0.0", + "System.Numerics.Vectors": "4.0.0.0" + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs index 9103dfdf66..97d3f840cb 100644 --- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs @@ -16,7 +16,6 @@ namespace ImageSharp.Drawing.Processors public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush where TColor : struct, IPackedPixel, IEquatable { - /// /// Gets the color for a single pixel. /// diff --git a/src/ImageSharp.Drawing/Draw.cs b/src/ImageSharp.Drawing/Draw.cs deleted file mode 100644 index 55dba9257d..0000000000 --- a/src/ImageSharp.Drawing/Draw.cs +++ /dev/null @@ -1,506 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.Numerics; - using Drawing; - using Drawing.Brushes; - using Drawing.Pens; - using Drawing.Processors; - using SixLabors.Shapes; - - /// - /// Extension methods for the type. - /// - public static partial class ImageExtensions - { - /// - /// Draws the outline of the polygon with the provided pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The shape. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, IPen pen, IShape shape, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(shape), options)); - } - - /// - /// Draws the outline of the polygon with the provided pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The shape. - /// The Image - public static Image DrawPolygon(this Image source, IPen pen, IShape shape) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(pen, shape, GraphicsOptions.Default); - } - - /// - /// Draws the outline of the polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The shape. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, IShape shape, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new Pen(brush, thickness), shape, options); - } - - /// - /// Draws the outline of the polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The shape. - /// The Image - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, IShape shape) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new Pen(brush, thickness), shape); - } - - /// - /// Draws the outline of the polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The shape. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, TColor color, float thickness, IShape shape, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new SolidBrush(color), thickness, shape, options); - } - - /// - /// Draws the outline of the polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The shape. - /// The Image - public static Image DrawPolygon(this Image source, TColor color, float thickness, IShape shape) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new SolidBrush(color), thickness, shape); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points)), options); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The Image - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points))); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The Image - public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new SolidBrush(color), thickness, points); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(new SolidBrush(color), thickness, points, options); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided Pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points)), options); - } - - /// - /// Draws the provided Points as a closed Linear Polygon with the provided Pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The Image - public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points))); - } - - /// - /// Draws the path with the provided pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The path. - /// The options. - /// - /// The Image - /// - public static Image DrawPath(this Image source, IPen pen, IPath path, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(path), options)); - } - - /// - /// Draws the path with the provided pen. - /// - /// The type of the color. - /// The source. - /// The pen. - /// The path. - /// The Image - public static Image DrawPath(this Image source, IPen pen, IPath path) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new DrawPathProcessor(pen, new ShapeRegion(path), GraphicsOptions.Default)); - } - - /// - /// Draws the path with the bursh at the privdied thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The path. - /// The options. - /// - /// The Image - /// - public static Image DrawPath(this Image source, IBrush brush, float thickness, IPath path, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), path, options); - } - - /// - /// Draws the path with the bursh at the privdied thickness. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The path. - /// The Image - public static Image DrawPath(this Image source, IBrush brush, float thickness, IPath path) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), path); - } - - /// - /// Draws the path with the bursh at the privdied thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The path. - /// The options. - /// - /// The Image - /// - public static Image DrawPath(this Image source, TColor color, float thickness, IPath path, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new SolidBrush(color), thickness, path, options); - } - - /// - /// Draws the path with the bursh at the privdied thickness. - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The path. - /// The Image - public static Image DrawPath(this Image source, TColor color, float thickness, IPath path) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new SolidBrush(color), thickness, path); - } - - /// - /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), new Path(new LinearLineSegment(points)), options); - } - - /// - /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The Image - public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), new Path(new LinearLineSegment(points))); - } - - /// - /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The Image - public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawLines(new SolidBrush(color), thickness, points); - } - - /// - /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawLines(new SolidBrush(color), thickness, points, options); - } - - /// - /// Draws the provided Points as an open Linear path with the supplied pen - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawLines(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(pen, new Path(new LinearLineSegment(points)), options); - } - - /// - /// Draws the provided Points as an open Linear path with the supplied pen - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The Image - public static Image DrawLines(this Image source, IPen pen, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(pen, new Path(new LinearLineSegment(points))); - } - - /// - /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), new Path(new BezierLineSegment(points)), options); - } - - /// - /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The brush. - /// The thickness. - /// The points. - /// The Image - public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(new Pen(brush, thickness), new Path(new BezierLineSegment(points))); - } - - /// - /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The Image - public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawBeziers(new SolidBrush(color), thickness, points); - } - - /// - /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush - /// - /// The type of the color. - /// The source. - /// The color. - /// The thickness. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawBeziers(new SolidBrush(color), thickness, points, options); - } - - /// - /// Draws the provided Points as an open Bezier path with the supplied pen - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(pen, new Path(new BezierLineSegment(points)), options); - } - - /// - /// Draws the provided Points as an open Bezier path with the supplied pen - /// - /// The type of the color. - /// The source. - /// The pen. - /// The points. - /// The Image - public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - return source.DrawPath(pen, new Path(new BezierLineSegment(points))); - } - } -} diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp.Drawing/DrawPath.cs new file mode 100644 index 0000000000..828d50fb33 --- /dev/null +++ b/src/ImageSharp.Drawing/DrawPath.cs @@ -0,0 +1,123 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + using Drawing.Processors; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the outline of the region with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IPen pen, Path path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Apply(new DrawPathProcessor(pen, path, options)); + } + + /// + /// Draws the outline of the polygon with the provided pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, IPen pen, Path path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, path, GraphicsOptions.Default); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, IBrush brush, float thickness, Path path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), path, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The thickness. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, IBrush brush, float thickness, Path path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new Pen(brush, thickness), path); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The path. + /// The options. + /// + /// The Image + /// + public static Image Draw(this Image source, TColor color, float thickness, Path path, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, path, options); + } + + /// + /// Draws the outline of the polygon with the provided brush at the provided thickness. + /// + /// The type of the color. + /// The source. + /// The color. + /// The thickness. + /// The path. + /// + /// The Image + /// + public static Image Draw(this Image source, TColor color, float thickness, Path path) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(new SolidBrush(color), thickness, path); + } + } +} diff --git a/src/ImageSharp.Drawing/Fill.cs b/src/ImageSharp.Drawing/Fill.cs deleted file mode 100644 index f94d9ca6f9..0000000000 --- a/src/ImageSharp.Drawing/Fill.cs +++ /dev/null @@ -1,173 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.Numerics; - using Drawing; - using Drawing.Brushes; - using Drawing.Processors; - - using SixLabors.Shapes; - - /// - /// Extension methods for the type. - /// - public static partial class ImageExtensions - { - /// - /// Flood fills the image with the specified brush. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The Image - public static Image Fill(this Image source, IBrush brush) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new FillProcessor(brush)); - } - - /// - /// Flood fills the image with the specified color. - /// - /// The type of the color. - /// The source. - /// The color. - /// The Image - public static Image Fill(this Image source, TColor color) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Fill(new SolidBrush(color)); - } - - /// - /// Flood fills the image in the shape o fhte provided polygon with the specified brush.. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The shape. - /// The graphics options. - /// The Image - public static Image Fill(this Image source, IBrush brush, IShape shape, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new FillShapeProcessor(brush, new ShapeRegion(shape), options)); - } - - /// - /// Flood fills the image in the shape of the provided polygon with the specified brush. - /// - /// The type of the color. - /// The source. - /// The brush. - /// The shape. - /// The Image - public static Image Fill(this Image source, IBrush brush, IShape shape) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(new FillShapeProcessor(brush, new ShapeRegion(shape), GraphicsOptions.Default)); - } - - /// - /// Flood fills the image in the shape o fhte provided polygon with the specified brush.. - /// - /// The type of the color. - /// The source. - /// The color. - /// The shape. - /// The options. - /// - /// The Image - /// - public static Image Fill(this Image source, TColor color, IShape shape, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Fill(new SolidBrush(color), shape, options); - } - - /// - /// Flood fills the image in the shape o fhte provided polygon with the specified brush.. - /// - /// The type of the color. - /// The source. - /// The color. - /// The shape. - /// The Image - public static Image Fill(this Image source, TColor color, IShape shape) - where TColor : struct, IPackedPixel, IEquatable - { - return source.Fill(new SolidBrush(color), shape); - } - - /// - /// Flood fills the image in the shape of a Linear polygon described by the points - /// - /// The type of the color. - /// The source. - /// The brush. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - // using Polygon directly instead of LinearPolygon as its will have less indirection - return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options); - } - - /// - /// Flood fills the image in the shape of a Linear polygon described by the points - /// - /// The type of the color. - /// The source. - /// The brush. - /// The points. - /// The Image - public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - // using Polygon directly instead of LinearPolygon as its will have less indirection - return source.Fill(brush, new Polygon(new LinearLineSegment(points))); - } - - /// - /// Flood fills the image in the shape of a Linear polygon described by the points - /// - /// The type of the color. - /// The source. - /// The color. - /// The points. - /// The options. - /// - /// The Image - /// - public static Image FillPolygon(this Image source, TColor color, Vector2[] points, GraphicsOptions options) - where TColor : struct, IPackedPixel, IEquatable - { - // using Polygon directly instead of LinearPolygon as its will have less indirection - return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)), options); - } - - /// - /// Flood fills the image in the shape of a Linear polygon described by the points - /// - /// The type of the color. - /// The source. - /// The color. - /// The points. - /// The Image - public static Image FillPolygon(this Image source, TColor color, Vector2[] points) - where TColor : struct, IPackedPixel, IEquatable - { - // using Polygon directly instead of LinearPolygon as its will have less indirection - return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points))); - } - } -} diff --git a/src/ImageSharp.Drawing/FillRegion.cs b/src/ImageSharp.Drawing/FillRegion.cs new file mode 100644 index 0000000000..8d4f20b673 --- /dev/null +++ b/src/ImageSharp.Drawing/FillRegion.cs @@ -0,0 +1,111 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using Drawing; + using Drawing.Brushes; + using Drawing.Processors; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flood fills the image with the specified brush. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The Image + public static Image Fill(this Image source, IBrush brush) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Apply(new FillProcessor(brush)); + } + + /// + /// Flood fills the image with the specified color. + /// + /// The type of the color. + /// The source. + /// The color. + /// The Image + public static Image Fill(this Image source, TColor color) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color)); + } + + /// + /// Flood fills the image with in the region with the specified brush. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The region. + /// The graphics options. + /// + /// The Image + /// + public static Image Fill(this Image source, IBrush brush, Region region, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Apply(new FillRegionProcessor(brush, region, options)); + } + + /// + /// Flood fills the image with in the region with the specified brush. + /// + /// The type of the color. + /// The source. + /// The brush. + /// The region. + /// + /// The Image + /// + public static Image Fill(this Image source, IBrush brush, Region region) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(brush, region, GraphicsOptions.Default); + } + + /// + /// Flood fills the image with in the region with the specified color. + /// + /// The type of the color. + /// The source. + /// The color. + /// The region. + /// The options. + /// + /// The Image + /// + public static Image Fill(this Image source, TColor color, Region region, GraphicsOptions options) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), region, options); + } + + /// + /// Flood fills the image with in the region with the specified color. + /// + /// The type of the color. + /// The source. + /// The color. + /// The region. + /// + /// The Image + /// + public static Image Fill(this Image source, TColor color, Region region) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Fill(new SolidBrush(color), region); + } + } +} diff --git a/src/ImageSharp.Drawing/IDrawableRegion.cs b/src/ImageSharp.Drawing/IDrawableRegion.cs deleted file mode 100644 index 82e9c39acf..0000000000 --- a/src/ImageSharp.Drawing/IDrawableRegion.cs +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing -{ - using System.Numerics; - - /// - /// Represents a region with knowledge about its outline. - /// - /// - public interface IDrawableRegion : IRegion - { - /// - /// Gets the point information for the specified x and y location. - /// - /// The x. - /// The y. - /// Information about the point in relation to a drawable edge - PointInfo GetPointInfo(int x, int y); - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Path.cs b/src/ImageSharp.Drawing/Path.cs new file mode 100644 index 0000000000..a997fa18f7 --- /dev/null +++ b/src/ImageSharp.Drawing/Path.cs @@ -0,0 +1,57 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + /// + /// Represents a something that has knowledge about its outline. + /// + public abstract class Path + { + /// + /// Gets the maximum number of intersections to could be returned. + /// + /// + /// The maximum intersections. + /// + public abstract int MaxIntersections { get; } + + /// + /// Gets the bounds. + /// + /// + /// The bounds. + /// + public abstract Rectangle Bounds { get; } + + /// + /// Gets the point information for the specified x and y location. + /// + /// The x. + /// The y. + /// Information about the point in relation to a drawable edge + public abstract PointInfo GetPointInfo(int x, int y); + + /// + /// Scans the X axis for intersections. + /// + /// The x. + /// The buffer. + /// The length. + /// The offset. + /// The number of intersections found. + public abstract int ScanX(int x, float[] buffer, int length, int offset); + + /// + /// Scans the Y axis for intersections. + /// + /// The position along the y axis to find intersections. + /// The buffer. + /// The length. + /// The offset. + /// The number of intersections found. + public abstract int ScanY(int y, float[] buffer, int length, int offset); + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index bbb5e1ab6c..1513443c4e 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -12,7 +12,6 @@ namespace ImageSharp.Drawing.Processors using System.Threading.Tasks; using ImageSharp.Processing; using Pens; - using SixLabors.Shapes; using Rectangle = ImageSharp.Rectangle; /// @@ -27,7 +26,7 @@ namespace ImageSharp.Drawing.Processors private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor private readonly IPen pen; - private readonly IDrawableRegion region; + private readonly Path region; private readonly GraphicsOptions options; /// @@ -36,7 +35,7 @@ namespace ImageSharp.Drawing.Processors /// The pen. /// The region. /// The options. - public DrawPathProcessor(IPen pen, IDrawableRegion region, GraphicsOptions options) + public DrawPathProcessor(IPen pen, Path region, GraphicsOptions options) { this.region = region; this.pen = pen; diff --git a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs similarity index 95% rename from src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs rename to src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index bdec022d49..2f6f8af7ba 100644 --- a/src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -11,30 +11,28 @@ namespace ImageSharp.Drawing.Processors using System.Threading.Tasks; using Drawing; using ImageSharp.Processing; - using SixLabors.Shapes; - using Rectangle = ImageSharp.Rectangle; /// /// Usinf a brsuh and a shape fills shape with contents of brush the /// /// The type of the color. /// - public class FillShapeProcessor : ImageProcessor + public class FillRegionProcessor : ImageProcessor where TColor : struct, IPackedPixel, IEquatable { private const float AntialiasFactor = 1f; private const int DrawPadding = 1; private readonly IBrush fillColor; - private readonly IRegion region; + private readonly Region region; private readonly GraphicsOptions options; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The brush. /// The region. /// The options. - public FillShapeProcessor(IBrush brush, IRegion region, GraphicsOptions options) + public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options) { this.region = region; this.fillColor = brush; @@ -89,6 +87,12 @@ namespace ImageSharp.Drawing.Processors return; } + if (pointsFound % 2 == 1) + { + // we seem to have just clipped a corner lets just skip it + return; + } + QuickSort(buffer, pointsFound); int currentIntersection = 0; @@ -96,13 +100,8 @@ namespace ImageSharp.Drawing.Processors float lastPoint = float.MinValue; 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)) @@ -232,6 +231,12 @@ namespace ImageSharp.Drawing.Processors return; } + if (pointsFound % 2 == 1) + { + // we seem to have just clipped a corner lets just skip it + return; + } + QuickSort(buffer, pointsFound); int currentIntersection = 0; diff --git a/src/ImageSharp.Drawing/IRegion.cs b/src/ImageSharp.Drawing/Region.cs similarity index 78% rename from src/ImageSharp.Drawing/IRegion.cs rename to src/ImageSharp.Drawing/Region.cs index 2264a91bee..95f0e17480 100644 --- a/src/ImageSharp.Drawing/IRegion.cs +++ b/src/ImageSharp.Drawing/Region.cs @@ -1,16 +1,14 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Drawing { - using System.Numerics; - /// /// Represents a region of an image. /// - public interface IRegion + public abstract class Region { /// /// Gets the maximum number of intersections to could be returned. @@ -18,7 +16,7 @@ namespace ImageSharp.Drawing /// /// The maximum intersections. /// - int MaxIntersections { get; } + public abstract int MaxIntersections { get; } /// /// Gets the bounds. @@ -26,7 +24,7 @@ namespace ImageSharp.Drawing /// /// The bounds. /// - Rectangle Bounds { get; } + public abstract Rectangle Bounds { get; } /// /// Scans the X axis for intersections. @@ -36,7 +34,7 @@ namespace ImageSharp.Drawing /// The length. /// The offset. /// The number of intersections found. - int ScanX(int x, float[] buffer, int length, int offset); + public abstract int ScanX(int x, float[] buffer, int length, int offset); /// /// Scans the Y axis for intersections. @@ -46,6 +44,6 @@ namespace ImageSharp.Drawing /// The length. /// The offset. /// The number of intersections found. - int ScanY(int y, float[] buffer, int length, int offset); + public abstract int ScanY(int y, float[] buffer, int length, int offset); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/project.json b/src/ImageSharp.Drawing/project.json index 5fcee9b41e..ff2900d9fa 100644 --- a/src/ImageSharp.Drawing/project.json +++ b/src/ImageSharp.Drawing/project.json @@ -44,7 +44,6 @@ "ImageSharp.Processing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-ci0047", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs index defb0e65e7..691955e8ed 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs @@ -39,7 +39,7 @@ namespace ImageSharp.Benchmarks { using (CoreImage image = new CoreImage(800, 800)) { - image.Fill(CoreColor.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)); + image.Fill(CoreColor.HotPink, new CoreRectangle(10, 10, 190, 140)); return new CoreSize(image.Width, image.Height); } diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json index 8650a8af41..866a36faae 100644 --- a/tests/ImageSharp.Benchmarks/project.json +++ b/tests/ImageSharp.Benchmarks/project.json @@ -16,32 +16,28 @@ "dependencies": { "BenchmarkDotNet.Diagnostics.Windows": "0.10.1", "ImageSharp": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Drawing": { - "target": "project", - "version": "1.0.0-*" + "target": "project" + }, + "ImageSharp.Drawing.Paths": { + "target": "project" }, "ImageSharp.Formats.Jpeg": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Png": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Bmp": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Gif": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" + "target": "project" } }, "commands": { diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 75212d3617..1bce8003ea 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -179,8 +179,11 @@ ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\ImageSharp.Drawing.dll + + ..\..\src\ImageSharp.Drawing.Paths\bin\$(Configuration)\net461\ImageSharp.Drawing.Paths.dll + - ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\SixLabors.Shapes.dll + ..\..\src\ImageSharp.Drawing.Paths\bin\$(Configuration)\net461\SixLabors.Shapes.dll ..\..\src\ImageSharp.Formats.Bmp\bin\$(Configuration)\net461\ImageSharp.Formats.Bmp.dll diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index 31aa87d4b7..f4465027df 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Drawing { using Drawing; using ImageSharp.Drawing; - using CorePath = SixLabors.Shapes.Path; + using ShapePath = SixLabors.Shapes.Path; using SixLabors.Shapes; using System; using System.Diagnostics.CodeAnalysis; @@ -33,13 +33,13 @@ namespace ImageSharp.Tests.Drawing new Vector2(60, 10), new Vector2(10, 400)); - CorePath p = new CorePath(linerSegemnt, bazierSegment); + ShapePath p = new ShapePath(linerSegemnt, bazierSegment); using (FileStream output = File.OpenWrite($"{path}/Simple.png")) { image .BackgroundColor(Color.Blue) - .DrawPath(Color.HotPink, 5, p) + .Draw(Color.HotPink, 5, p) .Save(output); } @@ -74,7 +74,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(60, 10), new Vector2(10, 400)); - CorePath p = new CorePath(linerSegemnt, bazierSegment); + ShapePath p = new ShapePath(linerSegemnt, bazierSegment); using (Image image = new Image(500, 500)) { @@ -82,7 +82,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPath(color, 10, p) + .Draw(color, 10, p) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index dd2ea5249c..03ec5d0c89 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -37,7 +37,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1)) + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) .Save(output); } @@ -87,7 +87,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 5, new ComplexPolygon(simplePath, hole1)) + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) .Save(output); } @@ -131,7 +131,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(37, 85), new Vector2(130, 40), new Vector2(65, 137)); - var clipped = simplePath.Clip(hole1); + using (Image image = new Image(500, 500)) { @@ -139,7 +139,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 5, clipped) + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) .Save(output); } @@ -185,7 +185,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Pens.Dash(Color.HotPink, 5), new ComplexPolygon(simplePath, hole1)) + .Draw(Pens.Dash(Color.HotPink, 5), simplePath.Clip(hole1)) .Save(output); } } @@ -213,7 +213,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(color, 5, new ComplexPolygon(simplePath, hole1)) + .Draw(color, 5, simplePath.Clip(hole1)) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs index f987440754..a166464c9e 100644 --- a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs @@ -97,7 +97,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .DrawPolygon(Color.HotPink, 10, new Rectangle(10, 10, 190, 140)) + .Draw(Color.HotPink, 10, new Rectangle(10, 10, 190, 140)) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 3e20b3a09a..d5b2067239 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Tests.Drawing { Assert.Equal(Color.HotPink, sourcePixels[11, 11]); - Assert.Equal(Color.HotPink, sourcePixels[200, 150]); + Assert.Equal(Color.HotPink, sourcePixels[199, 150]); Assert.Equal(Color.HotPink, sourcePixels[50, 50]); diff --git a/tests/ImageSharp.Tests/project.json b/tests/ImageSharp.Tests/project.json index 9f9c0c7150..2a01aff847 100644 --- a/tests/ImageSharp.Tests/project.json +++ b/tests/ImageSharp.Tests/project.json @@ -21,34 +21,30 @@ }, "dependencies": { "ImageSharp": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "xunit": "2.2.0-*", "dotnet-test-xunit": "2.2.0-*", "ImageSharp.Drawing": { - "target": "project", - "version": "1.0.0-*" + "target": "project" + }, + "ImageSharp.Drawing.Paths": { + "target": "project" }, "ImageSharp.Formats.Png": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Jpeg": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Bmp": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Formats.Gif": { - "target": "project", - "version": "1.0.0-*" + "target": "project" }, "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" + "target": "project" } }, "frameworks": { From ca01e617990e049e3a3be0968cb6155d2b7fc560 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 2 Feb 2017 10:41:07 +0000 Subject: [PATCH 04/19] use nuget.org feed --- NuGet.config | 1 - src/ImageSharp.Drawing.Paths/project.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 88d71e7bac..b2c967cc97 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,6 @@  - diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index cdc5d2244f..85ad75148b 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-ci0050", + "SixLabors.Shapes": "0.1.0-alpha0001", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" From 4b8dcc28ec2f0a72283b87e5754e541668ea7783 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 2 Feb 2017 11:10:51 +0000 Subject: [PATCH 05/19] update readme for new package --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d947f227e..96d14c8be3 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,9 @@ Packages include: Contains methods like Resize, Crop, Skew, Rotate - Anything that alters the dimensions of the image. Contains methods like Gaussian Blur, Pixelate, Edge Detection - Anything that maintains the original image dimensions. - **ImageSharp.Drawing** - Brushes and various drawing algorithms. + Brushes and various drawing algorithms, including drawing Images + - **ImageSharp.Drawing.Paths** + various vector drawing methods for drawing paths, polygons etc. ### Manual build From 885cc58485230b470f6242d90cdecce3d99c5b36 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 2 Feb 2017 13:22:24 +0000 Subject: [PATCH 06/19] update to alpha2 to fix beziers --- src/ImageSharp.Drawing.Paths/project.json | 2 +- tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index 85ad75148b..a186f362c7 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-alpha0001", + "SixLabors.Shapes": "0.1.0-alpha0002", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 82e4ac33e2..f63d90aa6e 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -5,8 +5,6 @@ namespace ImageSharp.Tests.Drawing { - using ImageSharp.Drawing.Shapes; - using System.IO; using System.Numerics; From 59c9b88cbdfa9c21fdeff65038bb9b7d698962f0 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 2 Feb 2017 19:28:19 +0000 Subject: [PATCH 07/19] added unit tests for Paths --- src/ImageSharp.Drawing.Paths/DrawPolygon.cs | 16 ++ .../{FillShapes.cs => FillShape.cs} | 2 +- .../RectangleExtensions.cs | 10 +- src/ImageSharp.Drawing.Paths/ShapePath.cs | 19 +- src/ImageSharp.Drawing.Paths/ShapeRegion.cs | 18 +- .../Processors/DrawPathProcessor.cs | 40 +++- .../Processors/FillRegionProcessor.cs | 49 +++-- src/ImageSharp/Image/ImageBase{TColor}.cs | 11 + .../Image/ImageProcessingExtensions.cs | 8 +- src/ImageSharp/Image/Image{TColor}.cs | 16 ++ .../Drawing/Paths/DrawBeziersTests.cs | 168 ++++++++++++++++ .../Drawing/Paths/DrawLinesTests.cs | 168 ++++++++++++++++ .../Drawing/Paths/DrawPath.cs | 156 +++++++++++++++ .../Drawing/Paths/DrawPolygon.cs | 168 ++++++++++++++++ .../Drawing/Paths/DrawRectangle.cs | 187 +++++++++++++++++ .../Drawing/Paths/DrawShape.cs | 156 +++++++++++++++ .../Drawing/Paths/Extensions.cs | 49 +++++ .../Drawing/Paths/FillPath.cs | 112 +++++++++++ .../Drawing/Paths/FillPolygon.cs | 111 +++++++++++ .../Drawing/Paths/FillRectangle.cs | 119 +++++++++++ .../Drawing/Paths/FillShape.cs | 108 ++++++++++ .../Drawing/Paths/ProcessorWatchingImage.cs | 38 ++++ .../Drawing/Paths/ShapePathTests.cs | 188 ++++++++++++++++++ .../Drawing/Paths/ShapeRegionTests.cs | 170 ++++++++++++++++ tests/ImageSharp.Tests/project.json | 4 +- 25 files changed, 2036 insertions(+), 55 deletions(-) rename src/ImageSharp.Drawing.Paths/{FillShapes.cs => FillShape.cs} (98%) create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs diff --git a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs index 73d8ec0e7f..571b13c1ee 100644 --- a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs +++ b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs @@ -84,6 +84,22 @@ namespace ImageSharp return source.DrawPolygon(new SolidBrush(color), thickness, points, options); } + /// + /// Draws the provided Points as a closed Linear Polygon with the provided Pen. + /// + /// The type of the color. + /// The source. + /// The pen. + /// The points. + /// + /// The Image + /// + public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points) + where TColor : struct, IPackedPixel, IEquatable + { + return source.Draw(pen, new Polygon(new LinearLineSegment(points)), GraphicsOptions.Default); + } + /// /// Draws the provided Points as a closed Linear Polygon with the provided Pen. /// diff --git a/src/ImageSharp.Drawing.Paths/FillShapes.cs b/src/ImageSharp.Drawing.Paths/FillShape.cs similarity index 98% rename from src/ImageSharp.Drawing.Paths/FillShapes.cs rename to src/ImageSharp.Drawing.Paths/FillShape.cs index 9fe473ee1c..6e50f73771 100644 --- a/src/ImageSharp.Drawing.Paths/FillShapes.cs +++ b/src/ImageSharp.Drawing.Paths/FillShape.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // diff --git a/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs index 05d6bb6ced..8369cc83f6 100644 --- a/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs +++ b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs @@ -26,11 +26,11 @@ namespace ImageSharp.Drawing.Processors /// A representation of this public static Rectangle Convert(this SixLabors.Shapes.Rectangle source) { - int y = (int)Math.Floor(source.Y); - int width = (int)Math.Ceiling(source.Size.Width); - int x = (int)Math.Floor(source.X); - int height = (int)Math.Ceiling(source.Size.Height); - return new Rectangle(x, y, width, height); + int left = (int)Math.Floor(source.Left); + int right = (int)Math.Ceiling(source.Right); + int top = (int)Math.Floor(source.Top); + int bottom = (int)Math.Ceiling(source.Bottom); + return new Rectangle(left, top, right - left, bottom - top); } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs index 63d5fc9e1b..cd994515ef 100644 --- a/src/ImageSharp.Drawing.Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -25,11 +25,6 @@ namespace ImageSharp.Drawing /// private readonly IShape shape; - /// - /// The drawable paths - /// - private readonly ImmutableArray paths; - /// /// Initializes a new instance of the class. /// @@ -58,9 +53,17 @@ namespace ImageSharp.Drawing /// The paths. private ShapePath(ImmutableArray paths) { - this.paths = paths; + this.Paths = paths; } + /// + /// Gets the drawable paths + /// + /// + /// The paths. + /// + public ImmutableArray Paths { get; } + /// /// Gets the maximum number of intersections to could be returned. /// @@ -163,9 +166,9 @@ namespace ImageSharp.Drawing SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); float distance = float.MaxValue; - for (int i = 0; i < this.paths.Length; i++) + for (int i = 0; i < this.Paths.Length; i++) { - var p = this.paths[i].Distance(point); + var p = this.Paths[i].Distance(point); if (p.DistanceFromPath < distance) { distance = p.DistanceFromPath; diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs index d1a59a99d9..b43ad26b46 100644 --- a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs +++ b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs @@ -20,11 +20,6 @@ namespace ImageSharp.Drawing /// internal class ShapeRegion : Region { - /// - /// The fillable shape - /// - private readonly IShape shape; - /// /// Initializes a new instance of the class. /// @@ -40,17 +35,22 @@ namespace ImageSharp.Drawing /// The shape. public ShapeRegion(IShape shape) { - this.shape = shape; + this.Shape = shape; this.Bounds = shape.Bounds.Convert(); } + /// + /// Gets the fillable shape + /// + public IShape Shape { get; } + /// /// Gets the maximum number of intersections to could be returned. /// /// /// The maximum intersections. /// - public override int MaxIntersections => this.shape.MaxIntersections; + public override int MaxIntersections => this.Shape.MaxIntersections; /// /// Gets the bounds. @@ -77,7 +77,7 @@ namespace ImageSharp.Drawing Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { - int count = this.shape.FindIntersections( + int count = this.Shape.FindIntersections( start, end, innerbuffer, @@ -114,7 +114,7 @@ namespace ImageSharp.Drawing Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { - int count = this.shape.FindIntersections( + int count = this.Shape.FindIntersections( start, end, innerbuffer, diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index 1513443c4e..3fe5570807 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -25,10 +25,6 @@ namespace ImageSharp.Drawing.Processors private const float AntialiasFactor = 1f; private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor - private readonly IPen pen; - private readonly Path region; - private readonly GraphicsOptions options; - /// /// Initializes a new instance of the class. /// @@ -37,16 +33,40 @@ namespace ImageSharp.Drawing.Processors /// The options. public DrawPathProcessor(IPen pen, Path region, GraphicsOptions options) { - this.region = region; - this.pen = pen; - this.options = options; + this.Path = region; + this.Pen = pen; + this.Options = options; } + /// + /// Gets the options. + /// + /// + /// The options. + /// + public GraphicsOptions Options { get; } + + /// + /// Gets the pen. + /// + /// + /// The pen. + /// + public IPen Pen { get; } + + /// + /// Gets the path. + /// + /// + /// The path. + /// + public Path Path { get; } + /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { using (PixelAccessor sourcePixels = source.Lock()) - using (PenApplicator applicator = this.pen.CreateApplicator(sourcePixels, this.region.Bounds)) + using (PenApplicator applicator = this.Pen.CreateApplicator(sourcePixels, this.Path.Bounds)) { var rect = RectangleF.Ceiling(applicator.RequiredRegion); @@ -89,7 +109,7 @@ namespace ImageSharp.Drawing.Processors { // TODO add find intersections code to skip and scan large regions of this. int offsetX = x - startX; - var info = this.region.GetPointInfo(offsetX, offsetY); + var info = this.Path.GetPointInfo(offsetX, offsetY); var color = applicator.GetColor(offsetX, offsetY, info); @@ -120,7 +140,7 @@ namespace ImageSharp.Drawing.Processors { return 1; } - else if (this.options.Antialias && distance < AntialiasFactor) + else if (this.Options.Antialias && distance < AntialiasFactor) { return 1 - (distance / AntialiasFactor); } diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 2f6f8af7ba..6719d365a9 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -22,9 +22,6 @@ namespace ImageSharp.Drawing.Processors { private const float AntialiasFactor = 1f; private const int DrawPadding = 1; - private readonly IBrush fillColor; - private readonly Region region; - private readonly GraphicsOptions options; /// /// Initializes a new instance of the class. @@ -34,15 +31,39 @@ namespace ImageSharp.Drawing.Processors /// The options. public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options) { - this.region = region; - this.fillColor = brush; - this.options = options; + this.Region = region; + this.Brush = brush; + this.Options = options; } + /// + /// Gets the brush. + /// + /// + /// The brush. + /// + public IBrush Brush { get; } + + /// + /// Gets the region. + /// + /// + /// The region. + /// + public Region Region { get; } + + /// + /// Gets the options. + /// + /// + /// The options. + /// + public GraphicsOptions Options { get; } + /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - Rectangle rect = RectangleF.Ceiling(this.region.Bounds); // rounds the points out away from the center + Rectangle rect = RectangleF.Ceiling(this.Region.Bounds); // rounds the points out away from the center int polyStartY = sourceRectangle.Y - DrawPadding; int polyEndY = sourceRectangle.Bottom + DrawPadding; @@ -62,10 +83,10 @@ namespace ImageSharp.Drawing.Processors ArrayPool arrayPool = ArrayPool.Shared; - int maxIntersections = this.region.MaxIntersections; + int maxIntersections = this.Region.MaxIntersections; using (PixelAccessor sourcePixels = source.Lock()) - using (BrushApplicator applicator = this.fillColor.CreateApplicator(sourcePixels, rect)) + using (BrushApplicator applicator = this.Brush.CreateApplicator(sourcePixels, rect)) { Parallel.For( minY, @@ -80,7 +101,7 @@ namespace ImageSharp.Drawing.Processors float right = endX; // foreach line we get all the points where this line crosses the polygon - int pointsFound = this.region.ScanY(y, buffer, maxIntersections, 0); + int pointsFound = this.Region.ScanY(y, buffer, maxIntersections, 0); if (pointsFound == 0) { // nothign on this line skip @@ -156,7 +177,7 @@ namespace ImageSharp.Drawing.Processors float opacity = 1; if (!isInside && !onCorner) { - if (this.options.Antialias) + if (this.Options.Antialias) { float distance = float.MaxValue; if (x == lastPoint || x == nextPoint) @@ -207,7 +228,7 @@ namespace ImageSharp.Drawing.Processors } }); - if (this.options.Antialias) + if (this.Options.Antialias) { // we only need to do the X can for antialiasing purposes Parallel.For( @@ -224,7 +245,7 @@ namespace ImageSharp.Drawing.Processors float right = polyEndY; // foreach line we get all the points where this line crosses the polygon - int pointsFound = this.region.ScanX(x, buffer, maxIntersections, 0); + int pointsFound = this.Region.ScanX(x, buffer, maxIntersections, 0); if (pointsFound == 0) { // nothign on this line skip @@ -314,7 +335,7 @@ namespace ImageSharp.Drawing.Processors float opacity = 1; if (!isInside && !onCorner) { - if (this.options.Antialias) + if (this.Options.Antialias) { float distance = float.MaxValue; if (y == lastPoint || y == nextPoint) diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 1b3abd360f..b179d1158e 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -7,6 +7,7 @@ namespace ImageSharp { using System; using System.Diagnostics; + using Processing; /// /// The base class of all images. Encapsulates the basic properties and methods required to manipulate @@ -120,6 +121,16 @@ namespace ImageSharp /// public Configuration Configuration { get; private set; } + /// + /// Applies the processor. + /// + /// The processor. + /// The rectangle. + public virtual void ApplyProcessor(IImageProcessor processor, Rectangle rectangle) + { + processor.Apply(this, rectangle); + } + /// public void Dispose() { diff --git a/src/ImageSharp/Image/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs index d9073ad16f..db07afe2ab 100644 --- a/src/ImageSharp/Image/ImageProcessingExtensions.cs +++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs @@ -41,13 +41,7 @@ namespace ImageSharp public static Image Apply(this Image source, Rectangle sourceRectangle, IImageProcessor processor) where TColor : struct, IPackedPixel, IEquatable { - processor.Apply(source, sourceRectangle); - - foreach (ImageFrame sourceFrame in source.Frames) - { - processor.Apply(sourceFrame, sourceRectangle); - } - + source.ApplyProcessor(processor, sourceRectangle); return source; } } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 5c83ef9bbd..84bae39cca 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -16,6 +16,7 @@ namespace ImageSharp using System.Threading.Tasks; using Formats; + using Processing; /// /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. @@ -219,6 +220,21 @@ namespace ImageSharp /// public ExifProfile ExifProfile { get; set; } + /// + /// Applies the processor to the image. + /// + /// The processor to apply to the image. + /// The structure that specifies the portion of the image object to draw. + public override void ApplyProcessor(IImageProcessor processor, Rectangle rectangle) + { + // we want to put this on on here as it gives us a really go place to test/verify processor settings + base.ApplyProcessor(processor, rectangle); + foreach (ImageFrame sourceFrame in this.Frames) + { + sourceFrame.ApplyProcessor(processor, rectangle); + } + } + /// /// Saves the image to the given stream using the currently loaded image format. /// diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs new file mode 100644 index 0000000000..967cd1970c --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs @@ -0,0 +1,168 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawBeziersTests : IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Firebrick, 99.9f); + Vector2[] points = new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + }; + private ProcessorWatchingImage img; + + public DrawBeziersTests() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_points() + { + img.DrawBeziers(brush, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_points_options() + { + img.DrawBeziers(brush, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_points() + { + img.DrawBeziers(color, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_points_options() + { + img.DrawBeziers(color, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_points() + { + img.DrawBeziers(pen, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_points_options() + { + img.DrawBeziers(pen, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs new file mode 100644 index 0000000000..3b203cdd88 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs @@ -0,0 +1,168 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawLinesTests : IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Gray, 99.9f); + Vector2[] points = new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + }; + private ProcessorWatchingImage img; + + public DrawLinesTests() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_points() + { + img.DrawLines(brush, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_points_options() + { + img.DrawLines(brush, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_points() + { + img.DrawLines(color, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_points_options() + { + img.DrawLines(color, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_points() + { + img.DrawLines(pen, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_points_options() + { + img.DrawLines(pen, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0]); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs new file mode 100644 index 0000000000..8ce7dcba26 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs @@ -0,0 +1,156 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawPath : IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Gray, 99.9f); + IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + private ProcessorWatchingImage img; + + public DrawPath() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_path() + { + img.Draw(brush, thickness, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_path_options() + { + img.Draw(brush, thickness, path, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_path() + { + img.Draw(color, thickness, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_path_options() + { + img.Draw(color, thickness, path, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_path() + { + img.Draw(pen, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_path_options() + { + img.Draw(pen, path, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(path, shapepath.Paths[0]); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs new file mode 100644 index 0000000000..9a931470dd --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs @@ -0,0 +1,168 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawPolygon : IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Gray, 99.9f); + Vector2[] points = new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + }; + private ProcessorWatchingImage img; + + public DrawPolygon() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_points() + { + img.DrawPolygon(brush, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_points_options() + { + img.DrawPolygon(brush, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_points() + { + img.DrawPolygon(color, thickness, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_points_options() + { + img.DrawPolygon(color, thickness, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_points() + { + img.DrawPolygon(pen, points); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_points_options() + { + img.DrawPolygon(pen, points, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var path = Assert.IsType(processor.Path); + Assert.NotEmpty(path.Paths); + + var vector = Assert.IsType(path.Paths[0].AsShape()); + var segment = Assert.IsType(vector.LineSegments[0]); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs new file mode 100644 index 0000000000..f6680bc9c7 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs @@ -0,0 +1,187 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawRectangle : IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Gray, 99.9f); + ImageSharp.Rectangle rectangle = new ImageSharp.Rectangle(10, 10, 98, 324); + + private ProcessorWatchingImage img; + + public DrawRectangle() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_rectangle() + { + img.Draw(brush, thickness, rectangle); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_rectangle_options() + { + img.Draw(brush, thickness, rectangle, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_rectangle() + { + img.Draw(color, thickness, rectangle); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_rectangle_options() + { + img.Draw(color, thickness, rectangle, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_rectangle() + { + img.Draw(pen, rectangle); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_rectangle_options() + { + img.Draw(pen, rectangle, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + + var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs new file mode 100644 index 0000000000..8572099db6 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs @@ -0,0 +1,156 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class DrawShape: IDisposable + { + float thickness = 7.2f; + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Pen pen = new Pen(Color.Gray, 99.9f); + IShape shape = new SixLabors.Shapes.Polygon(new LinearLineSegment(new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + private ProcessorWatchingImage img; + + public DrawShape() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_Thickness_shape() + { + img.Draw(brush, thickness, shape); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void Brush_Thickness_shape_options() + { + img.Draw(brush, thickness, shape, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(brush, pen.Brush); + Assert.Equal(thickness, pen.Width); + } + + [Fact] + public void color_Thickness_shape() + { + img.Draw(color, thickness, shape); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_Thickness_shape_options() + { + img.Draw(color, thickness, shape, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + var pen = Assert.IsType>(processor.Pen); + Assert.Equal(thickness, pen.Width); + + var brush = Assert.IsType>(pen.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void pen_shape() + { + img.Draw(pen, shape); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + Assert.Equal(pen, processor.Pen); + } + + [Fact] + public void pen_path_options() + { + img.Draw(pen, shape, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var shapepath = Assert.IsType(processor.Path); + Assert.NotEmpty(shapepath.Paths); + Assert.Equal(shape, shapepath.Paths[0].AsShape()); + + Assert.Equal(pen, processor.Pen); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs b/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs new file mode 100644 index 0000000000..37720253db --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs @@ -0,0 +1,49 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class Extensions + { + [Fact] + public void ConvertPointInfo() + { + SixLabors.Shapes.PointInfo src = new SixLabors.Shapes.PointInfo + { + ClosestPointOnPath = Vector2.UnitX, + SearchPoint = Vector2.UnitY, + DistanceAlongPath = 99f, + DistanceFromPath = 82f + }; + ImageSharp.Drawing.PointInfo info = src.Convert(); + + Assert.Equal(src.DistanceAlongPath, info.DistanceAlongPath); + Assert.Equal(src.DistanceFromPath, info.DistanceFromPath); + } + + [Theory] + [InlineData(0.5, 0.5, 5, 5, 0,0,6,6)] + [InlineData(1, 1, 5, 5, 1,1,5,5)] + public void ConvertRectangle(float x, float y, float width, float height, int expectedX, int expectedY, int expectedWidth, int expectedHeight) + { + SixLabors.Shapes.Rectangle src = new SixLabors.Shapes.Rectangle(x, y, width, height); + ImageSharp.Rectangle actual = src.Convert(); + + Assert.Equal(expectedX, actual.X); + Assert.Equal(expectedY, actual.Y); + Assert.Equal(expectedWidth, actual.Width); + Assert.Equal(expectedHeight, actual.Height); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs new file mode 100644 index 0000000000..04a2a82abb --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -0,0 +1,112 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class FillPath : IDisposable + { + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + private ProcessorWatchingImage img; + + public FillPath() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_path() + { + img.Fill(brush, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segments = Assert.IsType(polygon.LineSegments[0]); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void Brush_path_options() + { + img.Fill(brush, path, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segments = Assert.IsType(polygon.LineSegments[0]); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void color_path() + { + img.Fill(color, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segments = Assert.IsType(polygon.LineSegments[0]); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_path_options() + { + img.Fill(color, path, noneDefault); + + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segments = Assert.IsType(polygon.LineSegments[0]); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs new file mode 100644 index 0000000000..2c95eb2094 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -0,0 +1,111 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class FillPolygon : IDisposable + { + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + Vector2[] path = new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + }; + private ProcessorWatchingImage img; + + public FillPolygon() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_path() + { + img.FillPolygon(brush, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segemnt = Assert.IsType(polygon.LineSegments[0]); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void Brush_path_options() + { + img.FillPolygon(brush, path, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segemnt = Assert.IsType(polygon.LineSegments[0]); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void color_path() + { + img.FillPolygon(color, path); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segemnt = Assert.IsType(polygon.LineSegments[0]); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_path_options() + { + img.FillPolygon(color, path, noneDefault); + + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var polygon = Assert.IsType(region.Shape); + var segemnt = Assert.IsType(polygon.LineSegments[0]); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs new file mode 100644 index 0000000000..520b107b9a --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -0,0 +1,119 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class FillRectangle : IDisposable + { + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + ImageSharp.Rectangle rectangle = new ImageSharp.Rectangle(10, 10, 77, 76); + + private ProcessorWatchingImage img; + + public FillRectangle() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_path() + { + img.Fill(brush, rectangle); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var rect = Assert.IsType(region.Shape); + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void Brush_path_options() + { + img.Fill(brush, rectangle, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var rect = Assert.IsType(region.Shape); + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void color_path() + { + img.Fill(color, rectangle); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + var rect = Assert.IsType(region.Shape); + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_path_options() + { + img.Fill(color, rectangle, noneDefault); + + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + var rect = Assert.IsType(region.Shape); + Assert.Equal(rect.Location.X, rectangle.X); + Assert.Equal(rect.Location.Y, rectangle.Y); + Assert.Equal(rect.Size.Width, rectangle.Width); + Assert.Equal(rect.Size.Height, rectangle.Height); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs new file mode 100644 index 0000000000..26bf61b5c2 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs @@ -0,0 +1,108 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + + public class FillShape : IDisposable + { + GraphicsOptions noneDefault = new GraphicsOptions(); + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + IShape shape = new SixLabors.Shapes.Polygon(new LinearLineSegment(new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + private ProcessorWatchingImage img; + + public FillShape() + { + this.img = new Paths.ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void Brush_shape() + { + img.Fill(brush, shape); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + Assert.Equal(shape, region.Shape); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void Brush_shape_options() + { + img.Fill(brush, shape, noneDefault); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + Assert.Equal(shape, region.Shape); + + Assert.Equal(brush, processor.Brush); + } + + [Fact] + public void color_shape() + { + img.Fill(color, shape); + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + var region = Assert.IsType(processor.Region); + Assert.Equal(shape, region.Shape); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + } + + [Fact] + public void color_shape_options() + { + img.Fill(color, shape, noneDefault); + + + Assert.NotEmpty(img.ProcessorApplications); + var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + Assert.Equal(noneDefault, processor.Options); + + var region = Assert.IsType(processor.Region); + Assert.Equal(shape, region.Shape); + + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(color, brush.Color); + + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs new file mode 100644 index 0000000000..ad3d41bc66 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs @@ -0,0 +1,38 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using Processing; + using System.Collections.Generic; + + /// + /// Watches but does not actually run the processors against the image. + /// + /// + public class ProcessorWatchingImage : Image + { + public List ProcessorApplications { get; } = new List(); + + public ProcessorWatchingImage(int width, int height) + : base(width, height, Configuration.CreateDefaultInstance()) + { + } + + public override void ApplyProcessor(IImageProcessor processor, Rectangle rectangle) + { + ProcessorApplications.Add(new ProcessorDetails + { + processor = processor, + rectangle = rectangle + }); + } + + public struct ProcessorDetails + { + public IImageProcessor processor; + public Rectangle rectangle; + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs new file mode 100644 index 0000000000..24e921ccb6 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs @@ -0,0 +1,188 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + using Moq; + using System.Collections.Immutable; + + public class ShapePathTests + { + private readonly Mock pathMock1; + private readonly Mock pathMock2; + private readonly Mock shapeMock1; + private readonly SixLabors.Shapes.Rectangle bounds1; + + public ShapePathTests() + { + this.shapeMock1 = new Mock(); + this.pathMock2 = new Mock(); + this.pathMock1 = new Mock(); + + this.bounds1 = new SixLabors.Shapes.Rectangle(10.5f, 10, 10, 10); + pathMock1.Setup(x => x.Bounds).Returns(this.bounds1); + pathMock2.Setup(x => x.Bounds).Returns(this.bounds1); + shapeMock1.Setup(x => x.Bounds).Returns(this.bounds1); + // wire up the 2 mocks to reference eachother + pathMock1.Setup(x => x.AsShape()).Returns(() => shapeMock1.Object); + shapeMock1.Setup(x => x.Paths).Returns(() => ImmutableArray.Create(pathMock1.Object, pathMock2.Object)); + } + + [Fact] + public void ShapePathWithPath_CallsAsShape() + { + new ShapePath(pathMock1.Object); + + pathMock1.Verify(x => x.AsShape()); + } + + [Fact] + public void ShapePathFromPathConvertsBoundsDoesNotProxyToShape() + { + ShapePath region = new ShapePath(pathMock1.Object); + + Assert.Equal(Math.Floor(bounds1.Left), region.Bounds.Left); + Assert.Equal(Math.Ceiling(bounds1.Right), region.Bounds.Right); + + pathMock1.Verify(x => x.Bounds); + } + + [Fact] + public void ShapePathFromPathMaxIntersectionsProxyToShape() + { + ShapePath region = new ShapePath(pathMock1.Object); + + int i = region.MaxIntersections; + shapeMock1.Verify(x => x.MaxIntersections); + } + + [Fact] + public void ShapePathFromPathScanXProxyToShape() + { + int xToScan = 10; + ShapePath region = new ShapePath(pathMock1.Object); + + shapeMock1.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(xToScan, s.X); + Assert.Equal(xToScan, e.X); + Assert.True(s.Y < bounds1.Top); + Assert.True(e.Y > bounds1.Bottom); + }).Returns(0); + + int i = region.ScanX(xToScan, new float[0], 0, 0); + + shapeMock1.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapePathFromPathScanYProxyToShape() + { + int yToScan = 10; + ShapePath region = new ShapePath(pathMock1.Object); + + shapeMock1.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(yToScan, s.Y); + Assert.Equal(yToScan, e.Y); + Assert.True(s.X < bounds1.Left); + Assert.True(e.X > bounds1.Right); + }).Returns(0); + + int i = region.ScanY(yToScan, new float[0], 0, 0); + + shapeMock1.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + + [Fact] + public void ShapePathFromShapeScanXProxyToShape() + { + int xToScan = 10; + ShapePath region = new ShapePath(shapeMock1.Object); + + shapeMock1.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(xToScan, s.X); + Assert.Equal(xToScan, e.X); + Assert.True(s.Y < bounds1.Top); + Assert.True(e.Y > bounds1.Bottom); + }).Returns(0); + + int i = region.ScanX(xToScan, new float[0], 0, 0); + + shapeMock1.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapePathFromShapeScanYProxyToShape() + { + int yToScan = 10; + ShapePath region = new ShapePath(shapeMock1.Object); + + shapeMock1.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(yToScan, s.Y); + Assert.Equal(yToScan, e.Y); + Assert.True(s.X < bounds1.Left); + Assert.True(e.X > bounds1.Right); + }).Returns(0); + + int i = region.ScanY(yToScan, new float[0], 0, 0); + + shapeMock1.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapePathFromShapeConvertsBoundsProxyToShape() + { + ShapePath region = new ShapePath(shapeMock1.Object); + + Assert.Equal(Math.Floor(bounds1.Left), region.Bounds.Left); + Assert.Equal(Math.Ceiling(bounds1.Right), region.Bounds.Right); + + shapeMock1.Verify(x => x.Bounds); + } + + [Fact] + public void ShapePathFromShapeMaxIntersectionsProxyToShape() + { + ShapePath region = new ShapePath(shapeMock1.Object); + + int i = region.MaxIntersections; + shapeMock1.Verify(x => x.MaxIntersections); + } + + [Fact] + public void GetPointInfoCallAllPathsForShape() + { + ShapePath region = new ShapePath(shapeMock1.Object); + + ImageSharp.Drawing.PointInfo info = region.GetPointInfo(10, 1); + + pathMock1.Verify(x => x.Distance(new Vector2(10, 1)), Times.Once); + pathMock2.Verify(x => x.Distance(new Vector2(10, 1)), Times.Once); + } + + [Fact] + public void GetPointInfoCallSinglePathForPath() + { + ShapePath region = new ShapePath(pathMock1.Object); + + ImageSharp.Drawing.PointInfo info = region.GetPointInfo(10, 1); + + pathMock1.Verify(x => x.Distance(new Vector2(10, 1)), Times.Once); + pathMock2.Verify(x => x.Distance(new Vector2(10, 1)), Times.Never); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs new file mode 100644 index 0000000000..e983dce669 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs @@ -0,0 +1,170 @@ + +namespace ImageSharp.Tests.Drawing.Paths +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + using Moq; + using System.Collections.Immutable; + + public class ShapeRegionTests + { + private readonly Mock pathMock; + private readonly Mock shapeMock; + private readonly SixLabors.Shapes.Rectangle bounds; + + public ShapeRegionTests() + { + this.shapeMock = new Mock(); + this.pathMock = new Mock(); + + this.bounds = new SixLabors.Shapes.Rectangle(10.5f, 10, 10, 10); + shapeMock.Setup(x => x.Bounds).Returns(this.bounds); + // wire up the 2 mocks to reference eachother + pathMock.Setup(x => x.AsShape()).Returns(() => shapeMock.Object); + shapeMock.Setup(x => x.Paths).Returns(() => ImmutableArray.Create(pathMock.Object)); + } + + [Fact] + public void ShapeRegionWithPath_CallsAsShape() + { + new ShapeRegion(pathMock.Object); + + pathMock.Verify(x => x.AsShape()); + } + + [Fact] + public void ShapeRegionWithPath_RetainsShape() + { + ShapeRegion region = new ShapeRegion(pathMock.Object); + + Assert.Equal(shapeMock.Object, region.Shape); + } + + [Fact] + public void ShapeRegionFromPathConvertsBoundsProxyToShape() + { + ShapeRegion region = new ShapeRegion(pathMock.Object); + + Assert.Equal(Math.Floor(bounds.Left), region.Bounds.Left); + Assert.Equal(Math.Ceiling(bounds.Right), region.Bounds.Right); + + shapeMock.Verify(x => x.Bounds); + } + + [Fact] + public void ShapeRegionFromPathMaxIntersectionsProxyToShape() + { + ShapeRegion region = new ShapeRegion(pathMock.Object); + + int i = region.MaxIntersections; + shapeMock.Verify(x => x.MaxIntersections); + } + + [Fact] + public void ShapeRegionFromPathScanXProxyToShape() + { + int xToScan = 10; + ShapeRegion region = new ShapeRegion(pathMock.Object); + + shapeMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(xToScan, s.X); + Assert.Equal(xToScan, e.X); + Assert.True(s.Y < bounds.Top); + Assert.True(e.Y > bounds.Bottom); + }).Returns(0); + + int i = region.ScanX(xToScan, new float[0], 0, 0); + + shapeMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapeRegionFromPathScanYProxyToShape() + { + int yToScan = 10; + ShapeRegion region = new ShapeRegion(pathMock.Object); + + shapeMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(yToScan, s.Y); + Assert.Equal(yToScan, e.Y); + Assert.True(s.X < bounds.Left); + Assert.True(e.X > bounds.Right); + }).Returns(0); + + int i = region.ScanY(yToScan, new float[0], 0, 0); + + shapeMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + + [Fact] + public void ShapeRegionFromShapeScanXProxyToShape() + { + int xToScan = 10; + ShapeRegion region = new ShapeRegion(shapeMock.Object); + + shapeMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(xToScan, s.X); + Assert.Equal(xToScan, e.X); + Assert.True(s.Y < bounds.Top); + Assert.True(e.Y > bounds.Bottom); + }).Returns(0); + + int i = region.ScanX(xToScan, new float[0], 0, 0); + + shapeMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapeRegionFromShapeScanYProxyToShape() + { + int yToScan = 10; + ShapeRegion region = new ShapeRegion(shapeMock.Object); + + shapeMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, e, b, c, o) => { + Assert.Equal(yToScan, s.Y); + Assert.Equal(yToScan, e.Y); + Assert.True(s.X < bounds.Left); + Assert.True(e.X > bounds.Right); + }).Returns(0); + + int i = region.ScanY(yToScan, new float[0], 0, 0); + + shapeMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public void ShapeRegionFromShapeConvertsBoundsProxyToShape() + { + ShapeRegion region = new ShapeRegion(shapeMock.Object); + + Assert.Equal(Math.Floor(bounds.Left), region.Bounds.Left); + Assert.Equal(Math.Ceiling(bounds.Right), region.Bounds.Right); + + shapeMock.Verify(x => x.Bounds); + } + + [Fact] + public void ShapeRegionFromShapeMaxIntersectionsProxyToShape() + { + ShapeRegion region = new ShapeRegion(shapeMock.Object); + + int i = region.MaxIntersections; + shapeMock.Verify(x => x.MaxIntersections); + } + } +} diff --git a/tests/ImageSharp.Tests/project.json b/tests/ImageSharp.Tests/project.json index 2a01aff847..3761bb3858 100644 --- a/tests/ImageSharp.Tests/project.json +++ b/tests/ImageSharp.Tests/project.json @@ -45,7 +45,9 @@ }, "ImageSharp.Processing": { "target": "project" - } + }, + //alpha supports netstandard + "Moq": "4.6.38-alpha" }, "frameworks": { "netcoreapp1.1": { From 2c5f60d7a871cc9fe3a05c4d8ef089e58951cc96 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 2 Feb 2017 19:44:33 +0000 Subject: [PATCH 08/19] revert accident additions --- .travis.yml | 4 ++-- ConsoleApp1/ConsoleApp1.csproj | 8 -------- ConsoleApp1/Program.cs | 9 --------- 3 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 ConsoleApp1/ConsoleApp1.csproj delete mode 100644 ConsoleApp1/Program.cs diff --git a/.travis.yml b/.travis.yml index ca8b90a06a..172079df24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ branches: script: - dotnet restore - - dotnet build -c Release src/*/project.csproj - - dotnet test tests/ImageSharp.Tests/project.csproj -c Release -f "netcoreapp1.1" + - dotnet build -c Release src/*/project.json + - dotnet test tests/ImageSharp.Tests/project.json -c Release -f "netcoreapp1.1" env: global: diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj deleted file mode 100644 index 68b6f24237..0000000000 --- a/ConsoleApp1/ConsoleApp1.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - Exe - netcoreapp1.0 - - - \ No newline at end of file diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs deleted file mode 100644 index 104ecf0262..0000000000 --- a/ConsoleApp1/Program.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -class Program -{ - static void Main(string[] args) - { - Console.WriteLine("Hello World!"); - } -} \ No newline at end of file From 65ffb797e14a551ba85ed081ee61c383d4baf6be Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 09:17:52 +0000 Subject: [PATCH 09/19] fix test names & vars --- .../Drawing/Helpers/BezierPolygon.cs | 71 ------------------ .../Drawing/Helpers/LinearPolygon.cs | 71 ------------------ .../Drawing/LineComplexPolygonTests.cs | 32 ++++----- .../Drawing/Paths/DrawBeziersTests.cs | 72 +++++++++---------- .../Drawing/Paths/DrawLinesTests.cs | 72 +++++++++---------- .../Drawing/Paths/DrawPath.cs | 48 ++++++------- .../Drawing/Paths/DrawPolygon.cs | 72 +++++++++---------- .../Drawing/Paths/DrawRectangle.cs | 60 ++++++++-------- .../Drawing/Paths/DrawShape.cs | 48 ++++++------- .../Drawing/Paths/FillPath.cs | 52 +++++++------- .../Drawing/Paths/FillPolygon.cs | 45 ++++++------ .../Drawing/Paths/FillRectangle.cs | 37 +++++----- .../Drawing/Paths/FillShape.cs | 31 ++++---- .../Drawing/Paths/ProcessorWatchingImage.cs | 4 ++ .../Drawing/Paths/ShapePathTests.cs | 2 +- .../Drawing/Paths/ShapeRegionTests.cs | 4 +- .../Drawing/SolidBezierTests.cs | 4 +- .../Drawing/SolidComplexPolygonTests.cs | 24 +++---- 18 files changed, 304 insertions(+), 445 deletions(-) delete mode 100644 tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs delete mode 100644 tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs diff --git a/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs b/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs deleted file mode 100644 index 070e555016..0000000000 --- a/tests/ImageSharp.Tests/Drawing/Helpers/BezierPolygon.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace SixLabors.Shapes -{ - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Numerics; - - using SixLabors.Shapes; - public class BezierPolygon : IShape - { - private Polygon polygon; - - public BezierPolygon(params Vector2[] points) - { - this.polygon = new Polygon(new BezierLineSegment(points)); - } - - public float Distance(Vector2 point) - { - return this.polygon.Distance(point); - } - - public bool Contains(Vector2 point) - { - return this.polygon.Contains(point); - } - - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - return this.polygon.FindIntersections(start, end, buffer, count, offset); - } - - public IEnumerable FindIntersections(Vector2 start, Vector2 end) - { - return this.polygon.FindIntersections(start, end); - } - - public IShape Transform(Matrix3x2 matrix) - { - return ((IShape)this.polygon).Transform(matrix); - } - - public Rectangle Bounds - { - get - { - return this.polygon.Bounds; - } - } - - public ImmutableArray Paths - { - get - { - return this.polygon.Paths; - } - } - - public int MaxIntersections - { - get - { - return this.polygon.MaxIntersections; - } - } - } -} diff --git a/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs b/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs deleted file mode 100644 index fa94882665..0000000000 --- a/tests/ImageSharp.Tests/Drawing/Helpers/LinearPolygon.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace SixLabors.Shapes -{ - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Numerics; - - using SixLabors.Shapes; - public class LinearPolygon : IShape - { - private Polygon polygon; - - public LinearPolygon(params Vector2[] points) - { - this.polygon = new Polygon(new LinearLineSegment(points)); - } - - public float Distance(Vector2 point) - { - return this.polygon.Distance(point); - } - - public bool Contains(Vector2 point) - { - return this.polygon.Contains(point); - } - - public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset) - { - return this.polygon.FindIntersections(start, end, buffer, count, offset); - } - - public IEnumerable FindIntersections(Vector2 start, Vector2 end) - { - return this.polygon.FindIntersections(start, end); - } - - public IShape Transform(Matrix3x2 matrix) - { - return ((IShape)this.polygon).Transform(matrix); - } - - public Rectangle Bounds - { - get - { - return this.polygon.Bounds; - } - } - - public ImmutableArray Paths - { - get - { - return this.polygon.Paths; - } - } - - public int MaxIntersections - { - get - { - return this.polygon.MaxIntersections; - } - } - } -} diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index 03ec5d0c89..0a4f2c4a06 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -71,15 +71,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByPolygonOutlineNoOverlapping() { string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(207, 25), new Vector2(263, 25), - new Vector2(235, 57)); + new Vector2(235, 57))); using (Image image = new Image(500, 500)) { @@ -122,15 +122,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByPolygonOutlineOverlapping() { string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(130, 40), - new Vector2(65, 137)); + new Vector2(65, 137))); using (Image image = new Image(500, 500)) @@ -169,15 +169,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByPolygonOutlineDashed() { string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(93, 85), - new Vector2(65, 137)); + new Vector2(65, 137))); using (Image image = new Image(500, 500)) { @@ -196,15 +196,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() { string path = this.CreateOutputDirectory("Drawing", "LineComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(93, 85), - new Vector2(65, 137)); + new Vector2(65, 137))); Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150); using (Image image = new Image(500, 500)) diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs index 967cd1970c..0d3b469812 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs @@ -40,127 +40,127 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_points() + public void CorrectlySetsBrushThicknessAndPoints() { img.DrawBeziers(brush, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_points_options() + public void CorrectlySetsBrushThicknessPointsAndOptions() { img.DrawBeziers(brush, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_points() + public void CorrectlySetsColorThicknessAndPoints() { img.DrawBeziers(color, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_points_options() + public void CorrectlySetsColorThicknessPointsAndOptions() { img.DrawBeziers(color, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_points() + public void CorrectlySetsPenAndPoints() { img.DrawBeziers(pen, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } [Fact] - public void pen_points_options() + public void CorrectlySetsPenPointsAndOptions() { img.DrawBeziers(pen, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs index 3b203cdd88..bbed3cae67 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs @@ -40,127 +40,127 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_points() + public void CorrectlySetsBrushThicknessAndPoints() { img.DrawLines(brush, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_points_options() + public void CorrectlySetsBrushThicknessPointsAndOptions() { img.DrawLines(brush, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_points() + public void CorrectlySetsColorThicknessAndPoints() { img.DrawLines(color, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_points_options() + public void CorrectlySetsColorThicknessPointsAndOptions() { img.DrawLines(color, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_points() + public void CorrectlySetsPenAndPoints() { img.DrawLines(pen, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } [Fact] - public void pen_points_options() + public void CorrectlySetsPenPointsAndOptions() { img.DrawLines(pen, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0]); - var segment = Assert.IsType(vector.LineSegments[0]); + SixLabors.Shapes.Path vector = Assert.IsType(path.Paths[0]); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs index 8ce7dcba26..531546370d 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs @@ -40,96 +40,96 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_path() + public void CorrectlySetsBrushThicknessAndPath() { img.Draw(brush, thickness, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_path_options() + public void CorrectlySetsBrushThicknessPathAndOptions() { img.Draw(brush, thickness, path, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_path() + public void CorrectlySetsColorThicknessAndPath() { img.Draw(color, thickness, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_path_options() + public void CorrectlySetsColorThicknessPathAndOptions() { img.Draw(color, thickness, path, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_path() + public void CorrectlySetsPenAndPath() { img.Draw(pen, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); @@ -137,16 +137,16 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void pen_path_options() + public void CorrectlySetsPenPathAndOptions() { img.Draw(pen, path, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(path, shapepath.Paths[0]); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs index 9a931470dd..399e79dae1 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs @@ -40,127 +40,127 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_points() + public void CorrectlySetsBrushThicknessAndPoints() { img.DrawPolygon(brush, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_points_options() + public void CorrectlySetsBrushThicknessPointsAndOptions() { img.DrawPolygon(brush, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_points() + public void CorrectlySetsColorThicknessAndPoints() { img.DrawPolygon(color, thickness, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_points_options() + public void CorrectlySetsColorThicknessPointsAndOptions() { img.DrawPolygon(color, thickness, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_points() + public void CorrectlySetsPenAndPoints() { img.DrawPolygon(pen, points); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } [Fact] - public void pen_points_options() + public void CorrectlySetsPenPointsAndOptions() { img.DrawPolygon(pen, points, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var path = Assert.IsType(processor.Path); + ShapePath path = Assert.IsType(processor.Path); Assert.NotEmpty(path.Paths); - var vector = Assert.IsType(path.Paths[0].AsShape()); - var segment = Assert.IsType(vector.LineSegments[0]); + Polygon vector = Assert.IsType(path.Paths[0].AsShape()); + LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]); Assert.Equal(pen, processor.Pen); } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs index f6680bc9c7..3842063b3e 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawRectangle.cs @@ -36,122 +36,122 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_rectangle() + public void CorrectlySetsBrushThicknessAndRectangle() { img.Draw(brush, thickness, rectangle); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_rectangle_options() + public void CorrectlySetsBrushThicknessRectangleAndOptions() { img.Draw(brush, thickness, rectangle, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_rectangle() + public void CorrectlySetsColorThicknessAndRectangle() { img.Draw(color, thickness, rectangle); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_rectangle_options() + public void CorrectlySetsColorThicknessRectangleAndOptions() { img.Draw(color, thickness, rectangle, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_rectangle() + public void CorrectlySetsPenAndRectangle() { img.Draw(pen, rectangle); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); @@ -162,19 +162,19 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void pen_rectangle_options() + public void CorrectlySetsPenRectangleAndOptions() { img.Draw(pen, rectangle, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); - var rect = Assert.IsType(shapepath.Paths[0].AsShape()); + SixLabors.Shapes.Rectangle rect = Assert.IsType(shapepath.Paths[0].AsShape()); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs index 8572099db6..30a6646f40 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawShape.cs @@ -40,96 +40,96 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_Thickness_shape() + public void CorrectlySetsBrushThicknessAndShape() { img.Draw(brush, thickness, shape); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void Brush_Thickness_shape_options() + public void CorrectlySetsBrushThicknessShapeAndOptions() { img.Draw(brush, thickness, shape, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(brush, pen.Brush); Assert.Equal(thickness, pen.Width); } [Fact] - public void color_Thickness_shape() + public void CorrectlySetsColorThicknessAndShape() { img.Draw(color, thickness, shape); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_Thickness_shape_options() + public void CorrectlySetsColorThicknessShapeAndOptions() { img.Draw(color, thickness, shape, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); - var pen = Assert.IsType>(processor.Pen); + Pen pen = Assert.IsType>(processor.Pen); Assert.Equal(thickness, pen.Width); - var brush = Assert.IsType>(pen.Brush); + SolidBrush brush = Assert.IsType>(pen.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void pen_shape() + public void CorrectlySetsPenAndShape() { img.Draw(pen, shape); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); @@ -137,16 +137,16 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void pen_path_options() + public void CorrectlySetsPenShapeAndOptions() { img.Draw(pen, shape, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var shapepath = Assert.IsType(processor.Path); + ShapePath shapepath = Assert.IsType(processor.Path); Assert.NotEmpty(shapepath.Paths); Assert.Equal(shape, shapepath.Paths[0].AsShape()); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs index 04a2a82abb..5ba6580bd7 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -29,7 +29,7 @@ namespace ImageSharp.Tests.Drawing.Paths public FillPath() { - this.img = new Paths.ProcessorWatchingImage(10, 10); + this.img = new ProcessorWatchingImage(10, 10); } public void Dispose() @@ -38,75 +38,75 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_path() + public void CorrectlySetsBrushAndPath() { img.Fill(brush, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segments = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + + // path is converted to a polygon before filling + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]); Assert.Equal(brush, processor.Brush); } [Fact] - public void Brush_path_options() + public void CorrectlySetsBrushPathOptions() { img.Fill(brush, path, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segments = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]); Assert.Equal(brush, processor.Brush); } [Fact] - public void color_path() + public void CorrectlySetsColorAndPath() { img.Fill(color, path); - + Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segments = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_path_options() + public void CorrectlySetsColorPathAndOptions() { img.Fill(color, path, noneDefault); - Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segments = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segments = Assert.IsType(polygon.LineSegments[0]); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); - } } } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs index 2c95eb2094..ad72d4c4ee 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -38,73 +38,72 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_path() + public void CorrectlySetsBrushAndPath() { img.FillPolygon(brush, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segemnt = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segemnt = Assert.IsType(polygon.LineSegments[0]); Assert.Equal(brush, processor.Brush); } [Fact] - public void Brush_path_options() + public void CorrectlySetsBrushPathAndOptions() { img.FillPolygon(brush, path, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segemnt = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segemnt = Assert.IsType(polygon.LineSegments[0]); Assert.Equal(brush, processor.Brush); } [Fact] - public void color_path() + public void CorrectlySetsColorAndPath() { img.FillPolygon(color, path); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segemnt = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segemnt = Assert.IsType(polygon.LineSegments[0]); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_path_options() + public void CorrectlySetsColorPathAndOptions() { img.FillPolygon(color, path, noneDefault); - Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var polygon = Assert.IsType(region.Shape); - var segemnt = Assert.IsType(polygon.LineSegments[0]); + ShapeRegion region = Assert.IsType(processor.Region); + Polygon polygon = Assert.IsType(region.Shape); + LinearLineSegment segemnt = Assert.IsType(polygon.LineSegments[0]); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs index 520b107b9a..f6b1c4adef 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -34,17 +34,17 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_path() + public void CorrectlySetsBrushAndRectangle() { img.Fill(brush, rectangle); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var rect = Assert.IsType(region.Shape); + ShapeRegion region = Assert.IsType(processor.Region); + SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); @@ -54,17 +54,17 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_path_options() + public void CorrectlySetsBrushRectangleAndOptions() { img.Fill(brush, rectangle, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var rect = Assert.IsType(region.Shape); + ShapeRegion region = Assert.IsType(processor.Region); + SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); @@ -74,45 +74,44 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void color_path() + public void CorrectlySetsColorAndRectangle() { img.Fill(color, rectangle); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); - var rect = Assert.IsType(region.Shape); + ShapeRegion region = Assert.IsType(processor.Region); + SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_path_options() + public void CorrectlySetsColorRectangleAndOptions() { img.Fill(color, rectangle, noneDefault); - Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); - var rect = Assert.IsType(region.Shape); + ShapeRegion region = Assert.IsType(processor.Region); + SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); Assert.Equal(rect.Size.Height, rectangle.Height); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs index 26bf61b5c2..140870a3c2 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillShape.cs @@ -19,7 +19,7 @@ namespace ImageSharp.Tests.Drawing.Paths GraphicsOptions noneDefault = new GraphicsOptions(); Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Color.HotPink); - IShape shape = new SixLabors.Shapes.Polygon(new LinearLineSegment(new Vector2[] { + IShape shape = new Polygon(new LinearLineSegment(new Vector2[] { new Vector2(10,10), new Vector2(20,10), new Vector2(20,10), @@ -38,69 +38,68 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void Brush_shape() + public void CorrectlySetsBrushAndShape() { img.Fill(brush, shape); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); + ShapeRegion region = Assert.IsType(processor.Region); Assert.Equal(shape, region.Shape); Assert.Equal(brush, processor.Brush); } [Fact] - public void Brush_shape_options() + public void CorrectlySetsBrushShapeAndOptions() { img.Fill(brush, shape, noneDefault); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); + ShapeRegion region = Assert.IsType(processor.Region); Assert.Equal(shape, region.Shape); Assert.Equal(brush, processor.Brush); } [Fact] - public void color_shape() + public void CorrectlySetsColorAndShape() { img.Fill(color, shape); Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(GraphicsOptions.Default, processor.Options); - var region = Assert.IsType(processor.Region); + ShapeRegion region = Assert.IsType(processor.Region); Assert.Equal(shape, region.Shape); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } [Fact] - public void color_shape_options() + public void CorrectlySetsColorShapeAndOptions() { img.Fill(color, shape, noneDefault); - Assert.NotEmpty(img.ProcessorApplications); - var processor = Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); Assert.Equal(noneDefault, processor.Options); - var region = Assert.IsType(processor.Region); + ShapeRegion region = Assert.IsType(processor.Region); Assert.Equal(shape, region.Shape); - var brush = Assert.IsType>(processor.Brush); + SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(color, brush.Color); } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs index ad3d41bc66..3bb3b3e777 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs @@ -27,6 +27,10 @@ namespace ImageSharp.Tests.Drawing.Paths processor = processor, rectangle = rectangle }); + + // doesn't really apply the processor to the fake images as this is supposed + // to be just used to test which processor was finally applied and to interogate + // its settings } public struct ProcessorDetails diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs index 24e921ccb6..5fc9678461 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapePathTests.cs @@ -39,7 +39,7 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void ShapePathWithPath_CallsAsShape() + public void ShapePathWithPathCallsAsShape() { new ShapePath(pathMock1.Object); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs index e983dce669..6754949518 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs @@ -35,7 +35,7 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void ShapeRegionWithPath_CallsAsShape() + public void ShapeRegionWithPathCallsAsShape() { new ShapeRegion(pathMock.Object); @@ -43,7 +43,7 @@ namespace ImageSharp.Tests.Drawing.Paths } [Fact] - public void ShapeRegionWithPath_RetainsShape() + public void ShapeRegionWithPathRetainsShape() { ShapeRegion region = new ShapeRegion(pathMock.Object); diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index f63d90aa6e..80713468d4 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -30,7 +30,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink,new BezierPolygon(simplePath)) + .Fill(Color.HotPink, new Polygon(new BezierLineSegment(simplePath))) .Save(output); } @@ -71,7 +71,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(color, new BezierPolygon(simplePath)) + .Fill(color, new Polygon(new BezierLineSegment(simplePath))) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index a1973a280b..45ee59d665 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -19,15 +19,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByPolygonOutline() { string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(93, 85), - new Vector2(65, 137)); + new Vector2(65, 137))); using (Image image = new Image(500, 500)) { @@ -62,15 +62,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedPolygonOutlineWithOverlap() { string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(130, 40), - new Vector2(65, 137)); + new Vector2(65, 137))); using (Image image = new Image(500, 500)) { @@ -104,15 +104,15 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() { string path = this.CreateOutputDirectory("Drawing", "ComplexPolygon"); - LinearPolygon simplePath = new LinearPolygon( + Polygon simplePath = new Polygon(new LinearLineSegment( new Vector2(10, 10), new Vector2(200, 150), - new Vector2(50, 300)); + new Vector2(50, 300))); - LinearPolygon hole1 = new LinearPolygon( + Polygon hole1 = new Polygon(new LinearLineSegment( new Vector2(37, 85), new Vector2(93, 85), - new Vector2(65, 137)); + new Vector2(65, 137))); Color color = new Color(Color.HotPink.R, Color.HotPink.G, Color.HotPink.B, 150); using (Image image = new Image(500, 500)) From 7cc3ecee46b56387e8a0ebaad66c764b2dd1c16f Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 09:30:16 +0000 Subject: [PATCH 10/19] some cleanup --- src/ImageSharp.Drawing.Paths/ShapePath.cs | 18 +++++++++--------- src/ImageSharp.Drawing.Paths/ShapeRegion.cs | 12 ++++++------ src/ImageSharp.Drawing/DrawPath.cs | 12 ++++++------ .../{Path.cs => Drawable.cs} | 6 +++--- .../Processors/DrawPathProcessor.cs | 4 ++-- .../ImageSharp.Tests/Drawing/DrawPathTests.cs | 6 +++--- .../Drawing/LineComplexPolygonTests.cs | 13 ++++++------- tests/ImageSharp.Tests/Drawing/PolygonTests.cs | 2 +- .../Drawing/SolidComplexPolygonTests.cs | 8 ++++---- .../Drawing/SolidPolygonTests.cs | 6 +++--- 10 files changed, 43 insertions(+), 44 deletions(-) rename src/ImageSharp.Drawing/{Path.cs => Drawable.cs} (91%) diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs index cd994515ef..ee1f6e9d95 100644 --- a/src/ImageSharp.Drawing.Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Drawing /// /// A drawable mapping between a / and a drawable/fillable region. /// - internal class ShapePath : ImageSharp.Drawing.Path + internal class ShapePath : ImageSharp.Drawing.Drawable { /// /// The fillable shape @@ -92,8 +92,8 @@ namespace ImageSharp.Drawing /// public override int ScanX(int x, float[] buffer, int length, int offset) { - var start = new Vector2(x, this.Bounds.Top - 1); - var end = new Vector2(x, this.Bounds.Bottom + 1); + Vector2 start = new Vector2(x, this.Bounds.Top - 1); + Vector2 end = new Vector2(x, this.Bounds.Bottom + 1); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { @@ -104,7 +104,7 @@ namespace ImageSharp.Drawing length, 0); - for (var i = 0; i < count; i++) + for (int i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].Y; } @@ -129,8 +129,8 @@ namespace ImageSharp.Drawing /// public override int ScanY(int y, float[] buffer, int length, int offset) { - var start = new Vector2(float.MinValue, y); - var end = new Vector2(float.MaxValue, y); + Vector2 start = new Vector2(float.MinValue, y); + Vector2 end = new Vector2(float.MaxValue, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { @@ -141,7 +141,7 @@ namespace ImageSharp.Drawing length, 0); - for (var i = 0; i < count; i++) + for (int i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].X; } @@ -162,13 +162,13 @@ namespace ImageSharp.Drawing /// Information about the the point public override PointInfo GetPointInfo(int x, int y) { - var point = new Vector2(x, y); + Vector2 point = new Vector2(x, y); SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); float distance = float.MaxValue; for (int i = 0; i < this.Paths.Length; i++) { - var p = this.Paths[i].Distance(point); + SixLabors.Shapes.PointInfo p = this.Paths[i].Distance(point); if (p.DistanceFromPath < distance) { distance = p.DistanceFromPath; diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs index b43ad26b46..b6921f16ee 100644 --- a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs +++ b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs @@ -72,8 +72,8 @@ namespace ImageSharp.Drawing /// public override int ScanX(int x, float[] buffer, int length, int offset) { - var start = new Vector2(x, this.Bounds.Top - 1); - var end = new Vector2(x, this.Bounds.Bottom + 1); + Vector2 start = new Vector2(x, this.Bounds.Top - 1); + Vector2 end = new Vector2(x, this.Bounds.Bottom + 1); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { @@ -84,7 +84,7 @@ namespace ImageSharp.Drawing length, 0); - for (var i = 0; i < count; i++) + for (int i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].Y; } @@ -109,8 +109,8 @@ namespace ImageSharp.Drawing /// public override int ScanY(int y, float[] buffer, int length, int offset) { - var start = new Vector2(float.MinValue, y); - var end = new Vector2(float.MaxValue, y); + Vector2 start = new Vector2(float.MinValue, y); + Vector2 end = new Vector2(float.MaxValue, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { @@ -121,7 +121,7 @@ namespace ImageSharp.Drawing length, 0); - for (var i = 0; i < count; i++) + for (int i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].X; } diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp.Drawing/DrawPath.cs index 828d50fb33..fe833e3af9 100644 --- a/src/ImageSharp.Drawing/DrawPath.cs +++ b/src/ImageSharp.Drawing/DrawPath.cs @@ -28,7 +28,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, IPen pen, Path path, GraphicsOptions options) + public static Image Draw(this Image source, IPen pen, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { return source.Apply(new DrawPathProcessor(pen, path, options)); @@ -44,7 +44,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, IPen pen, Path path) + public static Image Draw(this Image source, IPen pen, Drawable path) where TColor : struct, IPackedPixel, IEquatable { return source.Draw(pen, path, GraphicsOptions.Default); @@ -62,7 +62,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, IBrush brush, float thickness, Path path, GraphicsOptions options) + public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { return source.Draw(new Pen(brush, thickness), path, options); @@ -79,7 +79,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, IBrush brush, float thickness, Path path) + public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path) where TColor : struct, IPackedPixel, IEquatable { return source.Draw(new Pen(brush, thickness), path); @@ -97,7 +97,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, TColor color, float thickness, Path path, GraphicsOptions options) + public static Image Draw(this Image source, TColor color, float thickness, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { return source.Draw(new SolidBrush(color), thickness, path, options); @@ -114,7 +114,7 @@ namespace ImageSharp /// /// The Image /// - public static Image Draw(this Image source, TColor color, float thickness, Path path) + public static Image Draw(this Image source, TColor color, float thickness, Drawable path) where TColor : struct, IPackedPixel, IEquatable { return source.Draw(new SolidBrush(color), thickness, path); diff --git a/src/ImageSharp.Drawing/Path.cs b/src/ImageSharp.Drawing/Drawable.cs similarity index 91% rename from src/ImageSharp.Drawing/Path.cs rename to src/ImageSharp.Drawing/Drawable.cs index a997fa18f7..b818273313 100644 --- a/src/ImageSharp.Drawing/Path.cs +++ b/src/ImageSharp.Drawing/Drawable.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,9 +6,9 @@ namespace ImageSharp.Drawing { /// - /// Represents a something that has knowledge about its outline. + /// Represents a path or set of paths that can be drawn as an outline. /// - public abstract class Path + public abstract class Drawable { /// /// Gets the maximum number of intersections to could be returned. diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index 3fe5570807..53f0408d47 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Drawing.Processors /// The pen. /// The region. /// The options. - public DrawPathProcessor(IPen pen, Path region, GraphicsOptions options) + public DrawPathProcessor(IPen pen, Drawable region, GraphicsOptions options) { this.Path = region; this.Pen = pen; @@ -60,7 +60,7 @@ namespace ImageSharp.Drawing.Processors /// /// The path. /// - public Path Path { get; } + public Drawable Path { get; } /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index f4465027df..fc231a89d5 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -33,13 +33,13 @@ namespace ImageSharp.Tests.Drawing new Vector2(60, 10), new Vector2(10, 400)); - ShapePath p = new ShapePath(linerSegemnt, bazierSegment); + ShapePath p = new ShapePath(linerSegemnt, bazierSegment); using (FileStream output = File.OpenWrite($"{path}/Simple.png")) { image .BackgroundColor(Color.Blue) - .Draw(Color.HotPink, 5, p) + .Draw(Color.HotPink, 5, p) .Save(output); } @@ -82,7 +82,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(color, 10, p) + .Draw(color, 10, p) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index 0a4f2c4a06..6153cb3105 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -37,8 +37,8 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) + .Save(output); } using (PixelAccessor sourcePixels = image.Lock()) @@ -87,7 +87,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) .Save(output); } @@ -131,7 +131,6 @@ namespace ImageSharp.Tests.Drawing new Vector2(37, 85), new Vector2(130, 40), new Vector2(65, 137))); - using (Image image = new Image(500, 500)) { @@ -139,7 +138,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) + .Draw(Color.HotPink, 5, simplePath.Clip(hole1)) .Save(output); } @@ -185,7 +184,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(Pens.Dash(Color.HotPink, 5), simplePath.Clip(hole1)) + .Draw(Pens.Dash(Color.HotPink, 5), simplePath.Clip(hole1)) .Save(output); } } @@ -213,7 +212,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(color, 5, simplePath.Clip(hole1)) + .Draw(color, 5, simplePath.Clip(hole1)) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs index a166464c9e..3e06ca918e 100644 --- a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs @@ -97,7 +97,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Draw(Color.HotPink, 10, new Rectangle(10, 10, 190, 140)) + .Draw(Color.HotPink, 10, new Rectangle(10, 10, 190, 140)) .Save(output); } diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index 45ee59d665..98ec9ff83e 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -35,7 +35,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, simplePath.Clip(hole1)) + .Fill(Color.HotPink, simplePath.Clip(hole1)) .Save(output); } @@ -78,7 +78,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, simplePath.Clip(hole1)) + .Fill(Color.HotPink, simplePath.Clip(hole1)) .Save(output); } @@ -121,8 +121,8 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(color, simplePath.Clip(hole1)) - .Save(output); + .Fill(color, simplePath.Clip(hole1)) + .Save(output); } //shift background color towards forground color by the opacity amount diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index d5b2067239..5533fbc0a5 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Tests.Drawing { Assert.Equal(Color.HotPink, sourcePixels[11, 11]); - Assert.Equal(Color.HotPink, sourcePixels[199, 150]); + Assert.Equal(Color.HotPink, sourcePixels[199, 150]); Assert.Equal(Color.HotPink, sourcePixels[50, 50]); @@ -144,14 +144,14 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledRectangle() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - + using (Image image = new Image(500, 500)) { using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, new SixLabors.Shapes.Rectangle(10,10, 190, 140)) + .Fill(Color.HotPink, new SixLabors.Shapes.Rectangle(10,10, 190, 140)) .Save(output); } From 7f9a32b80ac50b51147d6832888d4b38e7c0f770 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 09:51:54 +0000 Subject: [PATCH 11/19] removed extension method --- src/ImageSharp.Drawing.Paths/DrawLines.cs | 2 -- src/ImageSharp.Drawing/DrawImage.cs | 3 ++- .../Binarization/BinaryThreshold.cs | 3 ++- .../ColorMatrix/BlackWhite.cs | 3 ++- .../ColorMatrix/ColorBlindness.cs | 3 ++- .../ColorMatrix/Grayscale.cs | 3 ++- src/ImageSharp.Processing/ColorMatrix/Hue.cs | 3 ++- .../ColorMatrix/Kodachrome.cs | 3 ++- .../ColorMatrix/Lomograph.cs | 3 ++- .../ColorMatrix/Polaroid.cs | 3 ++- .../ColorMatrix/Saturation.cs | 3 ++- .../ColorMatrix/Sepia.cs | 3 ++- .../Convolution/BoxBlur.cs | 3 ++- .../Convolution/DetectEdges.cs | 3 ++- .../Convolution/GaussianBlur.cs | 3 ++- .../Convolution/GaussianSharpen.cs | 3 ++- src/ImageSharp.Processing/Effects/Alpha.cs | 3 ++- .../Effects/BackgroundColor.cs | 3 ++- .../Effects/Brightness.cs | 5 +++-- src/ImageSharp.Processing/Effects/Contrast.cs | 3 ++- src/ImageSharp.Processing/Effects/Invert.cs | 3 ++- .../Effects/OilPainting.cs | 3 ++- src/ImageSharp.Processing/Effects/Pixelate.cs | 3 ++- src/ImageSharp.Processing/Overlays/Glow.cs | 3 ++- .../Overlays/Vignette.cs | 3 ++- src/ImageSharp.Processing/Transforms/Crop.cs | 4 +++- .../Transforms/EntropyCrop.cs | 4 +++- src/ImageSharp.Processing/Transforms/Flip.cs | 4 +++- .../Transforms/Resize.cs | 3 ++- .../Transforms/Rotate.cs | 4 +++- src/ImageSharp.Processing/Transforms/Skew.cs | 4 +++- .../Image/ImageProcessingExtensions.cs | 19 +------------------ 32 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp.Drawing.Paths/DrawLines.cs b/src/ImageSharp.Drawing.Paths/DrawLines.cs index 2e4f849870..1ff58fd1de 100644 --- a/src/ImageSharp.Drawing.Paths/DrawLines.cs +++ b/src/ImageSharp.Drawing.Paths/DrawLines.cs @@ -13,8 +13,6 @@ namespace ImageSharp using Drawing.Processors; using SixLabors.Shapes; - using Path = SixLabors.Shapes.Path; - /// /// Extension methods for the type. /// diff --git a/src/ImageSharp.Drawing/DrawImage.cs b/src/ImageSharp.Drawing/DrawImage.cs index 4b3fd491da..2fba227ee6 100644 --- a/src/ImageSharp.Drawing/DrawImage.cs +++ b/src/ImageSharp.Drawing/DrawImage.cs @@ -51,7 +51,8 @@ namespace ImageSharp location = Point.Empty; } - return source.Apply(source.Bounds, new DrawImageProcessor(image, size, location, percent)); + source.ApplyProcessor(new DrawImageProcessor(image, size, location, percent), source.Bounds); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Binarization/BinaryThreshold.cs b/src/ImageSharp.Processing/Binarization/BinaryThreshold.cs index 1b5b6c9bbc..e59369349f 100644 --- a/src/ImageSharp.Processing/Binarization/BinaryThreshold.cs +++ b/src/ImageSharp.Processing/Binarization/BinaryThreshold.cs @@ -40,7 +40,8 @@ namespace ImageSharp public static Image BinaryThreshold(this Image source, float threshold, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new BinaryThresholdProcessor(threshold)); + source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs b/src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs index e172a21be0..05fb8f19c8 100644 --- a/src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs +++ b/src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs @@ -39,7 +39,8 @@ namespace ImageSharp public static Image BlackWhite(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new BlackWhiteProcessor()); + source.ApplyProcessor(new BlackWhiteProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs b/src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs index 2e90b059e7..30b28861d0 100644 --- a/src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs +++ b/src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs @@ -78,7 +78,8 @@ namespace ImageSharp break; } - return source.Apply(rectangle, processor); + source.ApplyProcessor(processor, rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Grayscale.cs b/src/ImageSharp.Processing/ColorMatrix/Grayscale.cs index f1a17c02b0..b2aadc46db 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Grayscale.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Grayscale.cs @@ -45,7 +45,8 @@ namespace ImageSharp ? (IImageProcessor)new GrayscaleBt709Processor() : new GrayscaleBt601Processor(); - return source.Apply(rectangle, processor); + source.ApplyProcessor(processor, rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Hue.cs b/src/ImageSharp.Processing/ColorMatrix/Hue.cs index f03f65692a..25fcc6c559 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Hue.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Hue.cs @@ -41,7 +41,8 @@ namespace ImageSharp public static Image Hue(this Image source, float degrees, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new HueProcessor(degrees)); + source.ApplyProcessor(new HueProcessor(degrees), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs b/src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs index 2592d80909..dab0224c3a 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs @@ -39,7 +39,8 @@ namespace ImageSharp public static Image Kodachrome(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new KodachromeProcessor()); + source.ApplyProcessor(new KodachromeProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Lomograph.cs b/src/ImageSharp.Processing/ColorMatrix/Lomograph.cs index 2605bc3011..df34dc52e9 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Lomograph.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Lomograph.cs @@ -39,7 +39,8 @@ namespace ImageSharp public static Image Lomograph(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new LomographProcessor()); + source.ApplyProcessor(new LomographProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Polaroid.cs b/src/ImageSharp.Processing/ColorMatrix/Polaroid.cs index 5c51a710bf..4bb8f82a31 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Polaroid.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Polaroid.cs @@ -39,7 +39,8 @@ namespace ImageSharp public static Image Polaroid(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new PolaroidProcessor()); + source.ApplyProcessor(new PolaroidProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Saturation.cs b/src/ImageSharp.Processing/ColorMatrix/Saturation.cs index 773329ea6c..a92483c9c3 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Saturation.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Saturation.cs @@ -41,7 +41,8 @@ namespace ImageSharp public static Image Saturation(this Image source, int amount, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new SaturationProcessor(amount)); + source.ApplyProcessor(new SaturationProcessor(amount), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/ColorMatrix/Sepia.cs b/src/ImageSharp.Processing/ColorMatrix/Sepia.cs index 3f29b93e59..1a8ec4b95e 100644 --- a/src/ImageSharp.Processing/ColorMatrix/Sepia.cs +++ b/src/ImageSharp.Processing/ColorMatrix/Sepia.cs @@ -39,7 +39,8 @@ namespace ImageSharp public static Image Sepia(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new SepiaProcessor()); + source.ApplyProcessor(new SepiaProcessor(), rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Convolution/BoxBlur.cs b/src/ImageSharp.Processing/Convolution/BoxBlur.cs index e16c30516d..a68c2fa44d 100644 --- a/src/ImageSharp.Processing/Convolution/BoxBlur.cs +++ b/src/ImageSharp.Processing/Convolution/BoxBlur.cs @@ -41,7 +41,8 @@ namespace ImageSharp public static Image BoxBlur(this Image source, int radius, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new BoxBlurProcessor(radius)); + source.ApplyProcessor(new BoxBlurProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Convolution/DetectEdges.cs b/src/ImageSharp.Processing/Convolution/DetectEdges.cs index 32fc167f1d..a61726e74e 100644 --- a/src/ImageSharp.Processing/Convolution/DetectEdges.cs +++ b/src/ImageSharp.Processing/Convolution/DetectEdges.cs @@ -146,7 +146,8 @@ namespace ImageSharp public static Image DetectEdges(this Image source, Rectangle rectangle, IEdgeDetectorProcessor filter) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, filter); + source.ApplyProcessor(filter, rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Convolution/GaussianBlur.cs b/src/ImageSharp.Processing/Convolution/GaussianBlur.cs index 7e8b9a4032..893ebb2646 100644 --- a/src/ImageSharp.Processing/Convolution/GaussianBlur.cs +++ b/src/ImageSharp.Processing/Convolution/GaussianBlur.cs @@ -41,7 +41,8 @@ namespace ImageSharp public static Image GaussianBlur(this Image source, float sigma, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new GaussianBlurProcessor(sigma)); + source.ApplyProcessor(new GaussianBlurProcessor(sigma), rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Convolution/GaussianSharpen.cs b/src/ImageSharp.Processing/Convolution/GaussianSharpen.cs index ef49104599..e3f8e995bc 100644 --- a/src/ImageSharp.Processing/Convolution/GaussianSharpen.cs +++ b/src/ImageSharp.Processing/Convolution/GaussianSharpen.cs @@ -41,7 +41,8 @@ namespace ImageSharp public static Image GaussianSharpen(this Image source, float sigma, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new GaussianSharpenProcessor(sigma)); + source.ApplyProcessor(new GaussianSharpenProcessor(sigma), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/Alpha.cs b/src/ImageSharp.Processing/Effects/Alpha.cs index 856276a89e..21b6dfbcbc 100644 --- a/src/ImageSharp.Processing/Effects/Alpha.cs +++ b/src/ImageSharp.Processing/Effects/Alpha.cs @@ -40,7 +40,8 @@ namespace ImageSharp public static Image Alpha(this Image source, int percent, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new AlphaProcessor(percent)); + source.ApplyProcessor(new AlphaProcessor(percent), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/BackgroundColor.cs b/src/ImageSharp.Processing/Effects/BackgroundColor.cs index ac1add3513..0f724c08c0 100644 --- a/src/ImageSharp.Processing/Effects/BackgroundColor.cs +++ b/src/ImageSharp.Processing/Effects/BackgroundColor.cs @@ -24,7 +24,8 @@ namespace ImageSharp public static Image BackgroundColor(this Image source, TColor color) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(source.Bounds, new BackgroundColorProcessor(color)); + source.ApplyProcessor(new BackgroundColorProcessor(color), source.Bounds); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/Brightness.cs b/src/ImageSharp.Processing/Effects/Brightness.cs index 8c9ff8946f..bf5500faf5 100644 --- a/src/ImageSharp.Processing/Effects/Brightness.cs +++ b/src/ImageSharp.Processing/Effects/Brightness.cs @@ -39,8 +39,9 @@ namespace ImageSharp /// The . public static Image Brightness(this Image source, int amount, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable - { - return source.Apply(rectangle, new BrightnessProcessor(amount)); + { + source.ApplyProcessor(new BrightnessProcessor(amount), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/Contrast.cs b/src/ImageSharp.Processing/Effects/Contrast.cs index 8310286825..f05eea6399 100644 --- a/src/ImageSharp.Processing/Effects/Contrast.cs +++ b/src/ImageSharp.Processing/Effects/Contrast.cs @@ -40,7 +40,8 @@ namespace ImageSharp public static Image Contrast(this Image source, int amount, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new ContrastProcessor(amount)); + source.ApplyProcessor(new ContrastProcessor(amount), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/Invert.cs b/src/ImageSharp.Processing/Effects/Invert.cs index 31e524000e..fff3108df4 100644 --- a/src/ImageSharp.Processing/Effects/Invert.cs +++ b/src/ImageSharp.Processing/Effects/Invert.cs @@ -38,7 +38,8 @@ namespace ImageSharp public static Image Invert(this Image source, Rectangle rectangle) where TColor : struct, IPackedPixel, IEquatable { - return source.Apply(rectangle, new InvertProcessor()); + source.ApplyProcessor(new InvertProcessor(), rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Effects/OilPainting.cs b/src/ImageSharp.Processing/Effects/OilPainting.cs index 463cfd675c..fbd7777110 100644 --- a/src/ImageSharp.Processing/Effects/OilPainting.cs +++ b/src/ImageSharp.Processing/Effects/OilPainting.cs @@ -49,7 +49,8 @@ namespace ImageSharp throw new ArgumentOutOfRangeException(nameof(brushSize)); } - return source.Apply(rectangle, new OilPaintingProcessor(levels, brushSize)); + source.ApplyProcessor(new OilPaintingProcessor(levels, brushSize), rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Effects/Pixelate.cs b/src/ImageSharp.Processing/Effects/Pixelate.cs index 92d1fdd698..77b014e73d 100644 --- a/src/ImageSharp.Processing/Effects/Pixelate.cs +++ b/src/ImageSharp.Processing/Effects/Pixelate.cs @@ -45,7 +45,8 @@ namespace ImageSharp throw new ArgumentOutOfRangeException(nameof(size)); } - return source.Apply(rectangle, new PixelateProcessor(size)); + source.ApplyProcessor(new PixelateProcessor(size), rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Overlays/Glow.cs b/src/ImageSharp.Processing/Overlays/Glow.cs index 6511407dad..91fbfc7f62 100644 --- a/src/ImageSharp.Processing/Overlays/Glow.cs +++ b/src/ImageSharp.Processing/Overlays/Glow.cs @@ -88,7 +88,8 @@ namespace ImageSharp processor.GlowColor = color; } - return source.Apply(rectangle, processor); + source.ApplyProcessor(processor, rectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Overlays/Vignette.cs b/src/ImageSharp.Processing/Overlays/Vignette.cs index f728a3e1c6..c6cd0ab1e8 100644 --- a/src/ImageSharp.Processing/Overlays/Vignette.cs +++ b/src/ImageSharp.Processing/Overlays/Vignette.cs @@ -90,7 +90,8 @@ namespace ImageSharp processor.VignetteColor = color; } - return source.Apply(rectangle, processor); + source.ApplyProcessor(processor, rectangle); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Transforms/Crop.cs b/src/ImageSharp.Processing/Transforms/Crop.cs index 09309a8053..bdcbe51d8a 100644 --- a/src/ImageSharp.Processing/Transforms/Crop.cs +++ b/src/ImageSharp.Processing/Transforms/Crop.cs @@ -41,7 +41,9 @@ namespace ImageSharp where TColor : struct, IPackedPixel, IEquatable { CropProcessor processor = new CropProcessor(cropRectangle); - return source.Apply(source.Bounds, processor); + + source.ApplyProcessor(processor, source.Bounds); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Transforms/EntropyCrop.cs b/src/ImageSharp.Processing/Transforms/EntropyCrop.cs index 8ba6baf19b..fcfcf3813e 100644 --- a/src/ImageSharp.Processing/Transforms/EntropyCrop.cs +++ b/src/ImageSharp.Processing/Transforms/EntropyCrop.cs @@ -25,7 +25,9 @@ namespace ImageSharp where TColor : struct, IPackedPixel, IEquatable { EntropyCropProcessor processor = new EntropyCropProcessor(threshold); - return source.Apply(source.Bounds, processor); + + source.ApplyProcessor(processor, source.Bounds); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Transforms/Flip.cs b/src/ImageSharp.Processing/Transforms/Flip.cs index 4b4c1b7d62..82b664eb14 100644 --- a/src/ImageSharp.Processing/Transforms/Flip.cs +++ b/src/ImageSharp.Processing/Transforms/Flip.cs @@ -26,7 +26,9 @@ namespace ImageSharp where TColor : struct, IPackedPixel, IEquatable { FlipProcessor processor = new FlipProcessor(flipType); - return source.Apply(source.Bounds, processor); + + source.ApplyProcessor(processor, source.Bounds); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Processing/Transforms/Resize.cs b/src/ImageSharp.Processing/Transforms/Resize.cs index 35ffc8b7dd..aa4bf2439f 100644 --- a/src/ImageSharp.Processing/Transforms/Resize.cs +++ b/src/ImageSharp.Processing/Transforms/Resize.cs @@ -167,7 +167,8 @@ namespace ImageSharp processor = new ResizeProcessor(sampler, width, height, targetRectangle); } - return source.Apply(sourceRectangle, processor); + source.ApplyProcessor(processor, sourceRectangle); + return source; } } } diff --git a/src/ImageSharp.Processing/Transforms/Rotate.cs b/src/ImageSharp.Processing/Transforms/Rotate.cs index b35bbc58ad..e9ed4e97c1 100644 --- a/src/ImageSharp.Processing/Transforms/Rotate.cs +++ b/src/ImageSharp.Processing/Transforms/Rotate.cs @@ -53,7 +53,9 @@ namespace ImageSharp where TColor : struct, IPackedPixel, IEquatable { RotateProcessor processor = new RotateProcessor { Angle = degrees, Expand = expand }; - return source.Apply(source.Bounds, processor); + + source.ApplyProcessor(processor, source.Bounds); + return source; } } } diff --git a/src/ImageSharp.Processing/Transforms/Skew.cs b/src/ImageSharp.Processing/Transforms/Skew.cs index 825dce5556..5a662c3004 100644 --- a/src/ImageSharp.Processing/Transforms/Skew.cs +++ b/src/ImageSharp.Processing/Transforms/Skew.cs @@ -41,7 +41,9 @@ namespace ImageSharp where TColor : struct, IPackedPixel, IEquatable { SkewProcessor processor = new SkewProcessor { AngleX = degreesX, AngleY = degreesY, Expand = expand }; - return source.Apply(source.Bounds, processor); + + source.ApplyProcessor(processor, source.Bounds); + return source; } } } diff --git a/src/ImageSharp/Image/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs index db07afe2ab..db8fb4baa7 100644 --- a/src/ImageSharp/Image/ImageProcessingExtensions.cs +++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs @@ -24,24 +24,7 @@ namespace ImageSharp public static Image Apply(this Image source, IImageProcessor processor) where TColor : struct, IPackedPixel, IEquatable { - return Apply(source, source.Bounds, processor); - } - - /// - /// Applies the processor to the image. - /// This method does not resize the target image. - /// - /// The pixel format. - /// The image this method extends. - /// - /// The structure that specifies the portion of the image object to draw. - /// - /// The processors to apply to the image. - /// The . - public static Image Apply(this Image source, Rectangle sourceRectangle, IImageProcessor processor) - where TColor : struct, IPackedPixel, IEquatable - { - source.ApplyProcessor(processor, sourceRectangle); + source.ApplyProcessor(processor, source.Bounds); return source; } } From 00d6047fac6785a23b98d13eb610e15ccd7fdd06 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 09:52:24 +0000 Subject: [PATCH 12/19] case fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96d14c8be3..79f8994629 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Packages include: - **ImageSharp.Drawing** Brushes and various drawing algorithms, including drawing Images - **ImageSharp.Drawing.Paths** - various vector drawing methods for drawing paths, polygons etc. + Various vector drawing methods for drawing paths, polygons etc. ### Manual build From b471a0cfbafc7ec4a02936cb777424e8f7b44fc2 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 10:21:50 +0000 Subject: [PATCH 13/19] xml doc fixes --- src/ImageSharp.Drawing.Paths/DrawBeziers.cs | 30 ++++++------- src/ImageSharp.Drawing.Paths/DrawLines.cs | 30 ++++++------- src/ImageSharp.Drawing.Paths/DrawPath.cs | 36 ++++++---------- src/ImageSharp.Drawing.Paths/DrawPolygon.cs | 32 ++++++-------- src/ImageSharp.Drawing.Paths/DrawRectangle.cs | 30 ++++++------- src/ImageSharp.Drawing.Paths/DrawShape.cs | 30 ++++++------- src/ImageSharp.Drawing.Paths/FillPaths.cs | 24 ++++------- src/ImageSharp.Drawing.Paths/FillPolygon.cs | 20 ++++----- src/ImageSharp.Drawing.Paths/FillRectangle.cs | 20 ++++----- src/ImageSharp.Drawing.Paths/FillShape.cs | 20 ++++----- .../PointInfoExtensions.cs | 2 +- .../RectangleExtensions.cs | 2 +- src/ImageSharp.Drawing.Paths/ShapePath.cs | 43 +++---------------- src/ImageSharp.Drawing.Paths/ShapeRegion.cs | 36 ++-------------- src/ImageSharp.Drawing/DrawPath.cs | 36 ++++++---------- src/ImageSharp.Drawing/Drawable.cs | 6 --- src/ImageSharp.Drawing/FillRegion.cs | 18 ++++---- .../Processors/DrawPathProcessor.cs | 10 ++--- .../Processors/FillRegionProcessor.cs | 6 +-- src/ImageSharp.Drawing/Region.cs | 13 +++--- 20 files changed, 149 insertions(+), 295 deletions(-) diff --git a/src/ImageSharp.Drawing.Paths/DrawBeziers.cs b/src/ImageSharp.Drawing.Paths/DrawBeziers.cs index 6515db5771..1a511d84d7 100644 --- a/src/ImageSharp.Drawing.Paths/DrawBeziers.cs +++ b/src/ImageSharp.Drawing.Paths/DrawBeziers.cs @@ -24,14 +24,12 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -42,11 +40,11 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -57,11 +55,11 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -72,14 +70,12 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawBeziers(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -90,13 +86,11 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path with the supplied pen /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -107,10 +101,10 @@ namespace ImageSharp /// Draws the provided Points as an open Bezier path with the supplied pen /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. - /// The Image + /// The . public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/DrawLines.cs b/src/ImageSharp.Drawing.Paths/DrawLines.cs index 1ff58fd1de..f6f8d8f6c9 100644 --- a/src/ImageSharp.Drawing.Paths/DrawLines.cs +++ b/src/ImageSharp.Drawing.Paths/DrawLines.cs @@ -22,14 +22,12 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -40,11 +38,11 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -55,11 +53,11 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -70,14 +68,12 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The .> public static Image DrawLines(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -88,13 +84,11 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path with the supplied pen /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawLines(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -105,10 +99,10 @@ namespace ImageSharp /// Draws the provided Points as an open Linear path with the supplied pen /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. - /// The Image + /// The . public static Image DrawLines(this Image source, IPen pen, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/DrawPath.cs b/src/ImageSharp.Drawing.Paths/DrawPath.cs index 201984e0ac..4e4275df6e 100644 --- a/src/ImageSharp.Drawing.Paths/DrawPath.cs +++ b/src/ImageSharp.Drawing.Paths/DrawPath.cs @@ -22,13 +22,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -39,12 +37,10 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, IPath path) where TColor : struct, IPackedPixel, IEquatable { @@ -55,14 +51,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -73,13 +67,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, IPath path) where TColor : struct, IPackedPixel, IEquatable { @@ -90,14 +82,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -108,13 +98,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, IPath path) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs index 571b13c1ee..28785e5cbf 100644 --- a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs +++ b/src/ImageSharp.Drawing.Paths/DrawPolygon.cs @@ -22,14 +22,12 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -40,11 +38,11 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -55,11 +53,11 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. - /// The Image + /// The . public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -70,14 +68,12 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawPolygon(this Image source, TColor color, float thickness, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -88,12 +84,10 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided Pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. - /// - /// The Image - /// + /// The . public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -104,13 +98,11 @@ namespace ImageSharp /// Draws the provided Points as a closed Linear Polygon with the provided Pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/DrawRectangle.cs b/src/ImageSharp.Drawing.Paths/DrawRectangle.cs index 28ea3d6e03..4e8ec7135b 100644 --- a/src/ImageSharp.Drawing.Paths/DrawRectangle.cs +++ b/src/ImageSharp.Drawing.Paths/DrawRectangle.cs @@ -23,13 +23,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -40,10 +38,10 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, IPen pen, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { @@ -54,14 +52,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -72,11 +68,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { @@ -87,14 +83,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -105,11 +99,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, TColor color, float thickness, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/DrawShape.cs b/src/ImageSharp.Drawing.Paths/DrawShape.cs index 15ae2b1797..6ddce65b98 100644 --- a/src/ImageSharp.Drawing.Paths/DrawShape.cs +++ b/src/ImageSharp.Drawing.Paths/DrawShape.cs @@ -22,13 +22,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -39,10 +37,10 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, IPen pen, IShape shape) where TColor : struct, IPackedPixel, IEquatable { @@ -53,14 +51,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -71,11 +67,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, IShape shape) where TColor : struct, IPackedPixel, IEquatable { @@ -86,14 +82,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -104,11 +98,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The shape. - /// The Image + /// The . public static Image Draw(this Image source, TColor color, float thickness, IShape shape) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/FillPaths.cs b/src/ImageSharp.Drawing.Paths/FillPaths.cs index 3095ee7cdf..09a799794c 100644 --- a/src/ImageSharp.Drawing.Paths/FillPaths.cs +++ b/src/ImageSharp.Drawing.Paths/FillPaths.cs @@ -22,13 +22,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The shape. /// The graphics options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -39,12 +37,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The path. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, IPath path) where TColor : struct, IPackedPixel, IEquatable { @@ -55,13 +51,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, IPath path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -72,12 +66,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The path. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, IPath path) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/FillPolygon.cs b/src/ImageSharp.Drawing.Paths/FillPolygon.cs index 4092e5fc64..a609ceed24 100644 --- a/src/ImageSharp.Drawing.Paths/FillPolygon.cs +++ b/src/ImageSharp.Drawing.Paths/FillPolygon.cs @@ -22,13 +22,11 @@ namespace ImageSharp /// Flood fills the image in the shape of a Linear polygon described by the points /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -39,10 +37,10 @@ namespace ImageSharp /// Flood fills the image in the shape of a Linear polygon described by the points /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The points. - /// The Image + /// The . public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { @@ -53,13 +51,11 @@ namespace ImageSharp /// Flood fills the image in the shape of a Linear polygon described by the points /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The points. /// The options. - /// - /// The Image - /// + /// The . public static Image FillPolygon(this Image source, TColor color, Vector2[] points, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -70,10 +66,10 @@ namespace ImageSharp /// Flood fills the image in the shape of a Linear polygon described by the points /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The points. - /// The Image + /// The . public static Image FillPolygon(this Image source, TColor color, Vector2[] points) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/FillRectangle.cs b/src/ImageSharp.Drawing.Paths/FillRectangle.cs index aef777edd2..579a288a48 100644 --- a/src/ImageSharp.Drawing.Paths/FillRectangle.cs +++ b/src/ImageSharp.Drawing.Paths/FillRectangle.cs @@ -20,13 +20,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -37,10 +35,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The shape. - /// The Image + /// The . public static Image Fill(this Image source, IBrush brush, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { @@ -51,13 +49,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, Rectangle shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -68,10 +64,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The shape. - /// The Image + /// The . public static Image Fill(this Image source, TColor color, Rectangle shape) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/FillShape.cs b/src/ImageSharp.Drawing.Paths/FillShape.cs index 6e50f73771..52a3c60dd5 100644 --- a/src/ImageSharp.Drawing.Paths/FillShape.cs +++ b/src/ImageSharp.Drawing.Paths/FillShape.cs @@ -22,13 +22,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The shape. /// The graphics options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -39,10 +37,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The shape. - /// The Image + /// The . public static Image Fill(this Image source, IBrush brush, IShape shape) where TColor : struct, IPackedPixel, IEquatable { @@ -53,13 +51,11 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The shape. /// The options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, IShape shape, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -70,10 +66,10 @@ namespace ImageSharp /// Flood fills the image in the shape of the provided polygon with the specified brush.. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The shape. - /// The Image + /// The . public static Image Fill(this Image source, TColor color, IShape shape) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs b/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs index ea38dfb9d3..18cd4e66c0 100644 --- a/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs +++ b/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Drawing /// /// Converts a to an ImageSharp . /// - /// The source. + /// The image this method extends. /// A representation of this public static PointInfo Convert(this SixLabors.Shapes.PointInfo source) { diff --git a/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs index 8369cc83f6..1faa6469ad 100644 --- a/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs +++ b/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Drawing.Processors /// /// Converts a Shaper2D to an ImageSharp by creating a the entirely surrounds the source. /// - /// The source. + /// The image this method extends. /// A representation of this public static Rectangle Convert(this SixLabors.Shapes.Rectangle source) { diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs index ee1f6e9d95..f2f07ea3cb 100644 --- a/src/ImageSharp.Drawing.Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -64,32 +64,13 @@ namespace ImageSharp.Drawing /// public ImmutableArray Paths { get; } - /// - /// Gets the maximum number of intersections to could be returned. - /// - /// - /// The maximum intersections. - /// + /// public override int MaxIntersections => this.shape.MaxIntersections; - /// - /// Gets the bounds. - /// - /// - /// The bounds. - /// + /// public override Rectangle Bounds { get; } - /// - /// Scans the X axis for intersections. - /// - /// The x. - /// The buffer. - /// The length. - /// The offset. - /// - /// The number of intersections found. - /// + /// public override int ScanX(int x, float[] buffer, int length, int offset) { Vector2 start = new Vector2(x, this.Bounds.Top - 1); @@ -117,16 +98,7 @@ namespace ImageSharp.Drawing } } - /// - /// Scans the Y axis for intersections. - /// - /// The position along the y axis to find intersections. - /// The buffer. - /// The length. - /// The offset. - /// - /// The number of intersections found. - /// + /// public override int ScanY(int y, float[] buffer, int length, int offset) { Vector2 start = new Vector2(float.MinValue, y); @@ -154,12 +126,7 @@ namespace ImageSharp.Drawing } } - /// - /// Gets the point information for the specified x and y location. - /// - /// The x. - /// The y. - /// Information about the the point + /// public override PointInfo GetPointInfo(int x, int y) { Vector2 point = new Vector2(x, y); diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs index b6921f16ee..a1fdd7b8c0 100644 --- a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs +++ b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs @@ -44,32 +44,13 @@ namespace ImageSharp.Drawing /// public IShape Shape { get; } - /// - /// Gets the maximum number of intersections to could be returned. - /// - /// - /// The maximum intersections. - /// + /// public override int MaxIntersections => this.Shape.MaxIntersections; - /// - /// Gets the bounds. - /// - /// - /// The bounds. - /// + /// public override Rectangle Bounds { get; } - /// - /// Scans the X axis for intersections. - /// - /// The x. - /// The buffer. - /// The length. - /// The offset. - /// - /// The number of intersections found. - /// + /// public override int ScanX(int x, float[] buffer, int length, int offset) { Vector2 start = new Vector2(x, this.Bounds.Top - 1); @@ -97,16 +78,7 @@ namespace ImageSharp.Drawing } } - /// - /// Scans the Y axis for intersections. - /// - /// The position along the y axis to find intersections. - /// The buffer. - /// The length. - /// The offset. - /// - /// The number of intersections found. - /// + /// public override int ScanY(int y, float[] buffer, int length, int offset) { Vector2 start = new Vector2(float.MinValue, y); diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp.Drawing/DrawPath.cs index fe833e3af9..d92731270f 100644 --- a/src/ImageSharp.Drawing/DrawPath.cs +++ b/src/ImageSharp.Drawing/DrawPath.cs @@ -21,13 +21,11 @@ namespace ImageSharp /// Draws the outline of the region with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -38,12 +36,10 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided pen. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The pen. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IPen pen, Drawable path) where TColor : struct, IPackedPixel, IEquatable { @@ -54,14 +50,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -72,13 +66,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The thickness. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path) where TColor : struct, IPackedPixel, IEquatable { @@ -89,14 +81,12 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The path. /// The options. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, Drawable path, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -107,13 +97,11 @@ namespace ImageSharp /// Draws the outline of the polygon with the provided brush at the provided thickness. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The thickness. /// The path. - /// - /// The Image - /// + /// The . public static Image Draw(this Image source, TColor color, float thickness, Drawable path) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing/Drawable.cs b/src/ImageSharp.Drawing/Drawable.cs index b818273313..62f5e62c14 100644 --- a/src/ImageSharp.Drawing/Drawable.cs +++ b/src/ImageSharp.Drawing/Drawable.cs @@ -13,17 +13,11 @@ namespace ImageSharp.Drawing /// /// Gets the maximum number of intersections to could be returned. /// - /// - /// The maximum intersections. - /// public abstract int MaxIntersections { get; } /// /// Gets the bounds. /// - /// - /// The bounds. - /// public abstract Rectangle Bounds { get; } /// diff --git a/src/ImageSharp.Drawing/FillRegion.cs b/src/ImageSharp.Drawing/FillRegion.cs index 8d4f20b673..c634d6e64b 100644 --- a/src/ImageSharp.Drawing/FillRegion.cs +++ b/src/ImageSharp.Drawing/FillRegion.cs @@ -20,9 +20,9 @@ namespace ImageSharp /// Flood fills the image with the specified brush. /// /// The type of the color. - /// The source. - /// The brush. - /// The Image + /// The image this method extends. + /// The details how to fill the region of interest. + /// The . public static Image Fill(this Image source, IBrush brush) where TColor : struct, IPackedPixel, IEquatable { @@ -33,9 +33,9 @@ namespace ImageSharp /// Flood fills the image with the specified color. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. - /// The Image + /// The . public static Image Fill(this Image source, TColor color) where TColor : struct, IPackedPixel, IEquatable { @@ -46,7 +46,7 @@ namespace ImageSharp /// Flood fills the image with in the region with the specified brush. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The region. /// The graphics options. @@ -63,7 +63,7 @@ namespace ImageSharp /// Flood fills the image with in the region with the specified brush. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The brush. /// The region. /// @@ -79,7 +79,7 @@ namespace ImageSharp /// Flood fills the image with in the region with the specified color. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The region. /// The options. @@ -96,7 +96,7 @@ namespace ImageSharp /// Flood fills the image with in the region with the specified color. /// /// The type of the color. - /// The source. + /// The image this method extends. /// The color. /// The region. /// diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index 53f0408d47..b4aa7fba5a 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -28,12 +28,12 @@ namespace ImageSharp.Drawing.Processors /// /// Initializes a new instance of the class. /// - /// The pen. - /// The region. - /// The options. - public DrawPathProcessor(IPen pen, Drawable region, GraphicsOptions options) + /// The details how to draw the outline/path. + /// The details of the paths and outlines to draw. + /// The drawing configuration options. + public DrawPathProcessor(IPen pen, Drawable drawable, GraphicsOptions options) { - this.Path = region; + this.Path = drawable; this.Pen = pen; this.Options = options; } diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 6719d365a9..67c3ad176c 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -26,9 +26,9 @@ namespace ImageSharp.Drawing.Processors /// /// Initializes a new instance of the class. /// - /// The brush. - /// The region. - /// The options. + /// The details how to fill the region of interest. + /// The region of interest to be filled. + /// The configuration options. public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options) { this.Region = region; diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs index 95f0e17480..81f3dca5bd 100644 --- a/src/ImageSharp.Drawing/Region.cs +++ b/src/ImageSharp.Drawing/Region.cs @@ -13,23 +13,20 @@ namespace ImageSharp.Drawing /// /// Gets the maximum number of intersections to could be returned. /// - /// - /// The maximum intersections. - /// public abstract int MaxIntersections { get; } /// - /// Gets the bounds. + /// Gets the bounding box that entirly surrounds this region. /// - /// - /// The bounds. - /// + /// + /// This should always contains all possible points returned from eather or . + /// public abstract Rectangle Bounds { get; } /// /// Scans the X axis for intersections. /// - /// The x. + /// The position along the X axies to find intersections. /// The buffer. /// The length. /// The offset. From 1275e42cec35e8f6230bbe2ee37016bf370d8541 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 10:26:50 +0000 Subject: [PATCH 14/19] xml doc fixes --- src/ImageSharp.Drawing/FillRegion.cs | 16 ++++------------ .../Processors/FillRegionProcessor.cs | 8 +------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp.Drawing/FillRegion.cs b/src/ImageSharp.Drawing/FillRegion.cs index c634d6e64b..fbbf659d1c 100644 --- a/src/ImageSharp.Drawing/FillRegion.cs +++ b/src/ImageSharp.Drawing/FillRegion.cs @@ -50,9 +50,7 @@ namespace ImageSharp /// The brush. /// The region. /// The graphics options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, Region region, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -66,9 +64,7 @@ namespace ImageSharp /// The image this method extends. /// The brush. /// The region. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, IBrush brush, Region region) where TColor : struct, IPackedPixel, IEquatable { @@ -83,9 +79,7 @@ namespace ImageSharp /// The color. /// The region. /// The options. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, Region region, GraphicsOptions options) where TColor : struct, IPackedPixel, IEquatable { @@ -99,9 +93,7 @@ namespace ImageSharp /// The image this method extends. /// The color. /// The region. - /// - /// The Image - /// + /// The . public static Image Fill(this Image source, TColor color, Region region) where TColor : struct, IPackedPixel, IEquatable { diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 67c3ad176c..6a37a1ae5b 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -39,17 +39,11 @@ namespace ImageSharp.Drawing.Processors /// /// Gets the brush. /// - /// - /// The brush. - /// public IBrush Brush { get; } /// - /// Gets the region. + /// Gets the region that this processor applies to. /// - /// - /// The region. - /// public Region Region { get; } /// From 506b59686b3e43368069adf948af991d13372182 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 10:32:54 +0000 Subject: [PATCH 15/19] xml doc fixes --- .../Brushes/Processors/BrushApplicator.cs | 12 ++++-------- .../Pens/Processors/PenApplicator.cs | 6 ++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs index 97d3f840cb..37af8cd046 100644 --- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs @@ -19,16 +19,12 @@ namespace ImageSharp.Drawing.Processors /// /// Gets the color for a single pixel. /// - /// The x. - /// The y. - /// - /// The color - /// + /// The x cordinate. + /// The y cordinate. + /// The a that should be applied to the pixel. public abstract TColor this[int x, int y] { get; } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// + /// public abstract void Dispose(); } } diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs index de680c809c..cba4d9fdc5 100644 --- a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs +++ b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs @@ -22,10 +22,8 @@ namespace ImageSharp.Drawing.Processors /// The required region. /// public abstract RectangleF RequiredRegion { get; } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// + + /// public abstract void Dispose(); /// From 1e79f41add09b3251b44846e7322079418d5efa5 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 10:57:00 +0000 Subject: [PATCH 16/19] fix stylecop issue --- src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs index cba4d9fdc5..86283b5bb6 100644 --- a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs +++ b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Drawing.Processors /// The required region. /// public abstract RectangleF RequiredRegion { get; } - + /// public abstract void Dispose(); From 2d3a9f1b0e053d9756aaf9d2f32f804f7d6f70b7 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 11:29:08 +0000 Subject: [PATCH 17/19] reduce calls --- .../PointInfoExtensions.cs | 27 ------------------- src/ImageSharp.Drawing.Paths/ShapePath.cs | 16 ++++++----- 2 files changed, 10 insertions(+), 33 deletions(-) delete mode 100644 src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs diff --git a/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs b/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs deleted file mode 100644 index 18cd4e66c0..0000000000 --- a/src/ImageSharp.Drawing.Paths/PointInfoExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing -{ - /// - /// Extension methods for helping to bridge Shaper2D and ImageSharp primitives. - /// - internal static class PointInfoExtensions - { - /// - /// Converts a to an ImageSharp . - /// - /// The image this method extends. - /// A representation of this - public static PointInfo Convert(this SixLabors.Shapes.PointInfo source) - { - return new PointInfo - { - DistanceAlongPath = source.DistanceAlongPath, - DistanceFromPath = source.DistanceFromPath - }; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs index f2f07ea3cb..8c9500e55f 100644 --- a/src/ImageSharp.Drawing.Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -130,20 +130,24 @@ namespace ImageSharp.Drawing public override PointInfo GetPointInfo(int x, int y) { Vector2 point = new Vector2(x, y); - SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); - float distance = float.MaxValue; + float distanceFromPath = float.MaxValue; + float distanceAlongPath = 0; for (int i = 0; i < this.Paths.Length; i++) { SixLabors.Shapes.PointInfo p = this.Paths[i].Distance(point); - if (p.DistanceFromPath < distance) + if (p.DistanceFromPath < distanceFromPath) { - distance = p.DistanceFromPath; - result = p; + distanceFromPath = p.DistanceFromPath; + distanceAlongPath = p.DistanceAlongPath; } } - return result.Convert(); + return new PointInfo + { + DistanceAlongPath = distanceAlongPath, + DistanceFromPath = distanceFromPath + }; } } } From a7fab63cb195af8962aacaf0a797b88acef266ae Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 11:36:37 +0000 Subject: [PATCH 18/19] remove old test --- .../ImageSharp.Tests/Drawing/Paths/Extensions.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs b/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs index 37720253db..a18dd90bc2 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs @@ -16,22 +16,6 @@ namespace ImageSharp.Tests.Drawing.Paths public class Extensions { - [Fact] - public void ConvertPointInfo() - { - SixLabors.Shapes.PointInfo src = new SixLabors.Shapes.PointInfo - { - ClosestPointOnPath = Vector2.UnitX, - SearchPoint = Vector2.UnitY, - DistanceAlongPath = 99f, - DistanceFromPath = 82f - }; - ImageSharp.Drawing.PointInfo info = src.Convert(); - - Assert.Equal(src.DistanceAlongPath, info.DistanceAlongPath); - Assert.Equal(src.DistanceFromPath, info.DistanceFromPath); - } - [Theory] [InlineData(0.5, 0.5, 5, 5, 0,0,6,6)] [InlineData(1, 1, 5, 5, 1,1,5,5)] From 8c2a840f4d990bb9115acd4c5e2a852e5cc99e86 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 3 Feb 2017 19:39:40 +0000 Subject: [PATCH 19/19] fixes some corner clipping issues --- src/ImageSharp.Drawing.Paths/ShapePath.cs | 4 +- src/ImageSharp.Drawing.Paths/ShapeRegion.cs | 4 +- src/ImageSharp.Drawing.Paths/project.json | 2 +- .../Processors/FillRegionProcessor.cs | 16 +++- .../Drawing/SolidPolygonTests.cs | 76 ++++++++++++++++++- 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing.Paths/ShapePath.cs index 8c9500e55f..34e77b8074 100644 --- a/src/ImageSharp.Drawing.Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing.Paths/ShapePath.cs @@ -101,8 +101,8 @@ namespace ImageSharp.Drawing /// public override int ScanY(int y, float[] buffer, int length, int offset) { - Vector2 start = new Vector2(float.MinValue, y); - Vector2 end = new Vector2(float.MaxValue, y); + Vector2 start = new Vector2(this.Bounds.Left - 1, y); + Vector2 end = new Vector2(this.Bounds.Right + 1, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs index a1fdd7b8c0..5adec67908 100644 --- a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs +++ b/src/ImageSharp.Drawing.Paths/ShapeRegion.cs @@ -81,8 +81,8 @@ namespace ImageSharp.Drawing /// public override int ScanY(int y, float[] buffer, int length, int offset) { - Vector2 start = new Vector2(float.MinValue, y); - Vector2 end = new Vector2(float.MaxValue, y); + Vector2 start = new Vector2(this.Bounds.Left - 1, y); + Vector2 end = new Vector2(this.Bounds.Right + 1, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index a186f362c7..1bd998ea79 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-alpha0002", + "SixLabors.Shapes": "0.1.0-alpha0003", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 6a37a1ae5b..4f1ee34ac1 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -57,7 +57,7 @@ namespace ImageSharp.Drawing.Processors /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - Rectangle rect = RectangleF.Ceiling(this.Region.Bounds); // rounds the points out away from the center + Rectangle rect = this.Region.Bounds; int polyStartY = sourceRectangle.Y - DrawPadding; int polyEndY = sourceRectangle.Bottom + DrawPadding; @@ -102,6 +102,13 @@ namespace ImageSharp.Drawing.Processors return; } + if (pointsFound == 1 && maxIntersections > 1) + { + // we must have clipped a corner lets just duplicate it into point 2 and continue :) + buffer[1] = buffer[0]; + pointsFound++; + } + if (pointsFound % 2 == 1) { // we seem to have just clipped a corner lets just skip it @@ -246,6 +253,13 @@ namespace ImageSharp.Drawing.Processors return; } + if (pointsFound == 1 && maxIntersections > 1) + { + // we must have clipped a corner lets just duplicate it into point 2 and continue :) + buffer[1] = buffer[0]; + pointsFound++; + } + if (pointsFound % 2 == 1) { // we seem to have just clipped a corner lets just skip it diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 5533fbc0a5..a41afd3334 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -13,6 +13,7 @@ namespace ImageSharp.Tests.Drawing using System.Numerics; using Xunit; using ImageSharp.Drawing.Brushes; + using SixLabors.Shapes; public class SolidPolygonTests : FileTestBase { @@ -151,7 +152,7 @@ namespace ImageSharp.Tests.Drawing { image .BackgroundColor(Color.Blue) - .Fill(Color.HotPink, new SixLabors.Shapes.Rectangle(10,10, 190, 140)) + .Fill(Color.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)) .Save(output); } @@ -169,5 +170,78 @@ namespace ImageSharp.Tests.Drawing } } } + + [Fact] + public void ImageShouldBeOverlayedByFilledTriangle() + { + string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); + + using (Image image = new Image(100, 100)) + { + using (FileStream output = File.OpenWrite($"{path}/Triangle.png")) + { + image + .BackgroundColor(Color.Blue) + .Fill(Color.HotPink, new RegularPolygon(50, 50, 3, 30)) + .Save(output); + } + + using (PixelAccessor sourcePixels = image.Lock()) + { + Assert.Equal(Color.HotPink, sourcePixels[25, 35]); + + Assert.Equal(Color.HotPink, sourcePixels[50, 79]); + + Assert.Equal(Color.HotPink, sourcePixels[75, 35]); + + Assert.Equal(Color.HotPink, sourcePixels[50, 50]); + + Assert.Equal(Color.Blue, sourcePixels[2, 2]); + + Assert.Equal(Color.Blue, sourcePixels[28, 60]); + + Assert.Equal(Color.Blue, sourcePixels[67, 67]); + } + } + } + + [Fact] + public void ImageShouldBeOverlayedByFilledSeptagon() + { + string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); + + var config = Configuration.CreateDefaultInstance(); + config.ParallelOptions.MaxDegreeOfParallelism = 1; + using (Image image = new Image(100, 100, config)) + { + using (FileStream output = File.OpenWrite($"{path}/Septagon.png")) + { + image + .BackgroundColor(Color.Blue) + .Fill(Color.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)) + .Save(output); + } + } + } + + [Fact] + public void ImageShouldBeOverlayedByFilledEllipse() + { + string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); + + var config = Configuration.CreateDefaultInstance(); + config.ParallelOptions.MaxDegreeOfParallelism = 1; + using (Image image = new Image(100, 100, config)) + { + using (FileStream output = File.OpenWrite($"{path}/ellipse.png")) + { + image + .BackgroundColor(Color.Blue) + .Fill(Color.HotPink, new Ellipse(50, 50, 30, 50) + .Rotate((float)(Math.PI / 3))) + .Save(output); + } + } + } } }