зеркало из https://github.com/SixLabors/Shapes.git
corner clipping now returns 2 points
This commit is contained in:
Родитель
c6ade382a6
Коммит
d726b97121
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче