Skip to content

Commit

Permalink
remove OrientationHandling
Browse files Browse the repository at this point in the history
  • Loading branch information
antonfirsov committed Nov 20, 2020
1 parent 3ff3e59 commit c221b81
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 54 deletions.
15 changes: 0 additions & 15 deletions src/ImageSharp.Drawing/Shapes/OrientationHandling.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static ScanEdgeCollection Create(
MemoryAllocator allocator,
int subsampling)
{
TessellatedMultipolygon multipolygon = TessellatedMultipolygon.Create(polygon, allocator, OrientationHandling.ForcePositiveOrientationOnSimplePolygons);
TessellatedMultipolygon multipolygon = TessellatedMultipolygon.Create(polygon, allocator);
return Create(multipolygon, allocator, subsampling);
}
}
Expand Down
59 changes: 21 additions & 38 deletions src/ImageSharp.Drawing/Shapes/TessellatedMultipolygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,32 @@ private TessellatedMultipolygon(Ring[] rings)
this.TotalVertexCount = rings.Sum(r => r.VertexCount);
}

private enum RingType
{
Contour,
Hole
}

public int TotalVertexCount { get; }

public int Count => this.rings.Length;

public Ring this[int index] => this.rings[index];

public static TessellatedMultipolygon Create(
IPath path,
MemoryAllocator memoryAllocator,
OrientationHandling orientationHandling = OrientationHandling.ForcePositiveOrientationOnSimplePolygons)
public static TessellatedMultipolygon Create(IPath path, MemoryAllocator memoryAllocator)
{
RingType? firstRingType = orientationHandling == OrientationHandling.FirstRingIsContourFollowedByHoles ? RingType.Contour : (RingType?)null;
RingType? followUpRingType = orientationHandling == OrientationHandling.FirstRingIsContourFollowedByHoles ? RingType.Hole : (RingType?)null;

// For now let's go with the assumption that first loop is always an external contour,
// and the rests are loops.
if (path is IInternalPathOwner ipo)
{
IReadOnlyList<InternalPath> internalPaths = ipo.GetRingsAsInternalPath();

// If we have only one ring, we may want to orient it as a contour
if (internalPaths.Count == 1 && orientationHandling != OrientationHandling.KeepOriginal)
{
firstRingType = RingType.Contour;
}
// If we have only one ring, we can change it's orientation without negative side-effects.
// Since the algorithm works best with positively-oriented polygons,
// we enforce the orientation for best output quality.
bool enforcePositiveOrientationOnFirstRing = internalPaths.Count == 1;

Ring[] rings = new Ring[internalPaths.Count];
var rings = new Ring[internalPaths.Count];
IMemoryOwner<PointF> pointBuffer = internalPaths[0].ExtractVertices(memoryAllocator);
RepeateFirstVertexAndEnsureOrientation(pointBuffer.Memory.Span, firstRingType);
RepeateFirstVertexAndEnsureOrientation(pointBuffer.Memory.Span, enforcePositiveOrientationOnFirstRing);
rings[0] = new Ring(pointBuffer);

for (int i = 1; i < internalPaths.Count; i++)
{
pointBuffer = internalPaths[i].ExtractVertices(memoryAllocator);
RepeateFirstVertexAndEnsureOrientation(pointBuffer.Memory.Span, followUpRingType);
RepeateFirstVertexAndEnsureOrientation(pointBuffer.Memory.Span, false);
rings[i] = new Ring(pointBuffer);
}

Expand All @@ -78,40 +63,38 @@ public static TessellatedMultipolygon Create(
{
ReadOnlyMemory<PointF>[] points = path.Flatten().Select(sp => sp.Points).ToArray();

// If we have only one ring, we may want to orient it as a contour
if (points.Length == 1 && orientationHandling != OrientationHandling.KeepOriginal)
{
firstRingType = RingType.Contour;
}
// If we have only one ring, we can change it's orientation without negative side-effects.
// Since the algorithm works best with positively-oriented polygons,
// we enforce the orientation for best output quality.
bool enforcePositiveOrientationOnFirstRing = points.Length == 1;

Ring[] rings = new Ring[points.Length];
rings[0] = MakeRing(points[0], firstRingType, memoryAllocator);
var rings = new Ring[points.Length];
rings[0] = MakeRing(points[0], enforcePositiveOrientationOnFirstRing, memoryAllocator);
for (int i = 1; i < points.Length; i++)
{
rings[i] = MakeRing(points[i], followUpRingType, memoryAllocator);
rings[i] = MakeRing(points[i], false, memoryAllocator);
}

return new TessellatedMultipolygon(rings);
}

static Ring MakeRing(ReadOnlyMemory<PointF> points, RingType? ringType, MemoryAllocator allocator)
static Ring MakeRing(ReadOnlyMemory<PointF> points, bool enforcePositiveOrientation, MemoryAllocator allocator)
{
IMemoryOwner<PointF> buffer = allocator.Allocate<PointF>(points.Length + 1);
Span<PointF> span = buffer.Memory.Span;
points.Span.CopyTo(span);
RepeateFirstVertexAndEnsureOrientation(span, ringType);
RepeateFirstVertexAndEnsureOrientation(span, enforcePositiveOrientation);
return new Ring(buffer);
}

static void RepeateFirstVertexAndEnsureOrientation(Span<PointF> span, RingType? ringType)
static void RepeateFirstVertexAndEnsureOrientation(Span<PointF> span, bool enforcePositiveOrientation)
{
// Repeat first vertex for perf:
span[span.Length - 1] = span[0];

if (ringType.HasValue)
if (enforcePositiveOrientation)
{
int orientation = ringType.Value == RingType.Contour ? 1 : -1;
TopologyUtilities.EnsureOrientation(span, orientation);
TopologyUtilities.EnsureOrientation(span, 1);
}
}
}
Expand Down Expand Up @@ -158,4 +141,4 @@ public void Dispose()
}
}
}
}
}

0 comments on commit c221b81

Please sign in to comment.