corner clipping now returns 2 points

This commit is contained in:
Scott Williams 2017-02-05 19:50:19 +00:00
Родитель c6ade382a6
Коммит d726b97121
5 изменённых файлов: 136 добавлений и 50 удалений

Просмотреть файл

@ -218,13 +218,21 @@ namespace SixLabors.Shapes
int position = 0;
Vector2 lastPoint = MaxVector;
int last = -1;
if (this.closedPath)
{
Vector2 point = FindIntersection(this.points[polyCorners - 1], this.points[0], start, end);
if (point != MaxVector)
{
lastPoint = point;
}
}
for (int i = 0; i < polyCorners && count > 0; i++)
{
int next = i + 1;
if (this.closedPath && next == polyCorners)
{
next = 0;
next -= polyCorners;
}
Vector2 point = FindIntersection(this.points[i], this.points[next], start, end);
@ -232,37 +240,37 @@ namespace SixLabors.Shapes
{
if (lastPoint.Equivelent(point, Epsilon))
{
lastPoint = MaxVector;;
int last = (i - 1 + polyCorners) % polyCorners;
// hit the same point a second time do we need to remove the old one if just clipping
var side = SideOfLine(this.points[last], start, end);
if(side != Side.Same && side == SideOfLine(this.points[next], start, end))
if (this.points[next].Equivelent(point, Epsilon))
{
buffer[position + offset] = point;
position++;
count--;
next = i;
}
if (this.points[last].Equivelent(point, Epsilon))
{
last = i;
}
var side = SideOfLine(this.points[last], start, end);
var side2 = SideOfLine(this.points[next], start, end);
if (side != side2)
{
// differnet side we skip adding as we are passing through it
continue;
}
}
else
{
// we are not double crossing so just add it once
buffer[position + offset] = point;
position++;
count--;
}
// record the last point sin the opposite direction
last = i;
// we are not double crossing so just add it once
buffer[position + offset] = point;
position++;
count--;
lastPoint = point;
}
}
// don't trim the last point
if(position > 1 && this.closedPath && buffer[offset].Equivelent(buffer[position + offset -1], Epsilon) )
{
// is the first point the same as the last point? and we are closed
// if so we have double counter and must "drop" the last one.
position--;
}
return position;
}
@ -308,43 +316,61 @@ namespace SixLabors.Shapes
}
// if it hit any points then class it as inside
foreach (var p in this.points)
{
if (p.Equivelent(point, Epsilon))
{
return true;
}
}
var topLeft = new Vector2(this.Bounds.Left - 1, this.Bounds.Top - 1);
var topRight = new Vector2(this.Bounds.Right + 1, this.Bounds.Top - 1);
var bottomLeft = new Vector2(this.Bounds.Left - 1, this.Bounds.Bottom + 1);
var bottomRight = new Vector2(this.Bounds.Right + 1, this.Bounds.Bottom + 1);
// get the point that cause the most intersections
var buffer = ArrayPool<Vector2>.Shared.Rent(this.points.Length);
try
{
var i = 0;
var c1 = (i = this.FindIntersections(point, topLeft, buffer, this.points.Length, 0)) % 2 == 1;
var c2 = (i = this.FindIntersections(point, topRight, buffer, this.points.Length, 0)) % 2 == 1;
var c3 = (i = this.FindIntersections(point, bottomLeft, buffer, this.points.Length, 0)) % 2 == 1;
var c4 = (i = this.FindIntersections(point, bottomRight, buffer, this.points.Length, 0)) % 2 == 1;
return c1 || c2 || c3 || c4;
var intersection = this.FindIntersections(point, MaxVector, buffer, this.points.Length, 0);
if (intersection % 2 == 1)
{
return true;
}
for (var i = 0; i < intersection; i++)
// get the point that cause the most intersections
{
if (buffer[i].Equivelent(point, Epsilon))
{
return true;
}
}
}
finally
{
ArrayPool<Vector2>.Shared.Return(buffer);
}
return false;
}
private static Side SideOfLine(Vector2 test, Vector2 lineStart, Vector2 lineEnd)
{
var testDiff = test - lineStart;
var lineDiff = lineEnd - lineStart;
if (float.IsInfinity(lineDiff.X))
{
if (lineDiff.X > 0)
{
lineDiff.X = float.MaxValue;
}
else
{
lineDiff.X = float.MinValue;
}
}
if (float.IsInfinity(lineDiff.Y))
{
if (lineDiff.Y > 0)
{
lineDiff.Y = float.MaxValue;
}
else
{
lineDiff.Y = float.MinValue;
}
}
var crossProduct = (lineDiff.X * testDiff.Y) - (lineDiff.Y * testDiff.X);
if (crossProduct == 0)
if (crossProduct > -Epsilon && crossProduct < Epsilon)
{
return Side.Same;
}

Просмотреть файл

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace SixLabors.Shapes.Tests
{
using System.Buffers;
using System.Numerics;
public class ComplexPolygonTests
{
[Fact]
public void MissingIntersection()
{
var data = new float[6];
Polygon simplePath = new Polygon(new LinearLineSegment(
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)));
Polygon hole1 = new Polygon(new LinearLineSegment(
new Vector2(65, 137),
new Vector2(37, 85),
new Vector2(93, 85)));
var intersections1 = ScanY(hole1, 137, data, 6, 0);
Assert.Equal(2, intersections1);
var poly = simplePath.Clip(hole1);
var intersections = ScanY(poly, 137, data, 6, 0);
// returns an even number of points
Assert.Equal(4, intersections);
}
public int ScanY(IShape shape, int y, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(shape.Bounds.Left - 1, y);
Vector2 end = new Vector2(shape.Bounds.Right + 1, y);
Vector2[] innerbuffer = ArrayPool<Vector2>.Shared.Rent(length);
try
{
int count = shape.FindIntersections(start, end, innerbuffer, length, 0);
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerbuffer[i].X;
}
return count;
}
finally
{
ArrayPool<Vector2>.Shared.Return(innerbuffer);
}
}
}
}

Просмотреть файл

@ -51,12 +51,12 @@ namespace SixLabors.Shapes.Tests
}
[Fact]
public void ClippingCornerShouldReturn1Points()
public void ClippingCornerShouldReturn2Points()
{
var poly = new Ellipse(50, 50, 30, 50);
var points = poly.FindIntersections(new Vector2(0, 75), new Vector2(100, 75)).ToArray();
Assert.Equal(1, points.Length);
Assert.Equal(2, points.Length);
}
[Fact]

Просмотреть файл

@ -280,7 +280,7 @@ namespace SixLabors.Shapes.Tests
var intersections = poly.FindIntersections(new Vector2(float.MinValue, 300), new Vector2(float.MaxValue, 300));
// returns an even number of points
Assert.Equal(1, intersections.Count());
Assert.Equal(2, intersections.Count());
}
[Fact]

Просмотреть файл

@ -109,12 +109,12 @@ namespace SixLabors.Shapes.Tests
}
[Fact]
public void ClippingCornerShouldReturn1Points()
public void ClippingCornerShouldReturn2Points()
{
var poly = new RegularPolygon(50, 50, 7, 30, -(float)Math.PI);
var points = poly.FindIntersections(new Vector2(0, 20), new Vector2(100, 20)).ToArray();
Assert.Equal(1, points.Length);
Assert.Equal(2, points.Length);
}
}
}