add IntersectsWith(PdfRectangle, PdfLine) and Intersect(PdfRectangle, PdfLine)

This commit is contained in:
BobLd 2020-09-15 11:41:24 +01:00
parent d29cc52973
commit 46b183f564
2 changed files with 144 additions and 1 deletions

View File

@ -13,7 +13,7 @@
/// </summary>
internal static class ClippingExtensions
{
private const double Factor = 10_000.0;
public const double Factor = 10_000.0;
/// <summary>
/// Number of lines to use when transforming bezier curve to polyline.
@ -220,5 +220,10 @@
{
return new ClipperIntPoint(point.X * Factor, point.Y * Factor);
}
internal static List<ClipperIntPoint> ToClipperIntPoint(this PdfLine line)
{
return new List<ClipperIntPoint>() { line.Point1.ToClipperIntPoint(), line.Point2.ToClipperIntPoint() };
}
}
}

View File

@ -475,6 +475,65 @@
var points = new[] { rectangle.BottomLeft, rectangle.BottomRight, rectangle.TopLeft, rectangle.TopRight };
return new PdfRectangle(points.Min(p => p.X), points.Min(p => p.Y), points.Max(p => p.X), points.Max(p => p.Y));
}
/// <summary>
/// Whether the rectangle and the line intersect.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="line"></param>
public static bool IntersectsWith(this PdfRectangle rectangle, PdfLine line)
{
return IntersectsWith(rectangle, line.Point1, line.Point2);
}
/// <summary>
/// Gets the <see cref="PdfLine"/> that is the intersection of the rectangle and the line.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="line"></param>
public static PdfLine? Intersect(this PdfRectangle rectangle, PdfLine line)
{
var i = Intersect(rectangle, line.Point1, line.Point2);
if (i != null)
{
return new PdfLine(i[0], i[1]);
}
return null;
}
/// <summary>
/// Gets the list of <see cref="PdfLine"/>s that are the intersection of the rectangle and the lines.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="lines"></param>
/// <returns></returns>
public static List<PdfLine> Intersect(this PdfRectangle rectangle, List<PdfLine> lines)
{
var clipper = new Clipper();
clipper.AddPath(rectangle.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true);
foreach (var line in lines)
{
clipper.AddPath(line.ToClipperIntPoint(), ClipperPolyType.Subject, false);
}
var solutions = new ClipperPolyTree();
if (clipper.Execute(ClipperClipType.Intersection, solutions))
{
List<PdfLine> rv = new List<PdfLine>();
foreach (var solution in solutions.Children)
{
rv.Add(new PdfLine(new PdfPoint(solution.Contour[0].X / ClippingExtensions.Factor, solution.Contour[0].Y / ClippingExtensions.Factor),
new PdfPoint(solution.Contour[1].X / ClippingExtensions.Factor, solution.Contour[1].Y / ClippingExtensions.Factor)));
}
return rv;
}
else
{
return new List<PdfLine>();
}
// clipper.clear() ??
}
#endregion
#region PdfLine
@ -533,6 +592,26 @@
{
return ParallelTo(line.Point1, line.Point2, other.From, other.To);
}
/// <summary>
/// Gets the <see cref="PdfLine"/> that is the intersection of the rectangle and the line.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="line"></param>
public static PdfLine? Intersect(this PdfLine line, PdfRectangle rectangle)
{
return rectangle.Intersect(line);
}
/// <summary>
/// Whether the rectangle and the line intersect.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="line"></param>
public static bool IntersectsWith(this PdfLine line, PdfRectangle rectangle)
{
return rectangle.IntersectsWith(line);
}
#endregion
#region Path Line
@ -657,6 +736,65 @@
}
}
/// <summary>
/// The intersection of the line formed by <paramref name="pl1"/> and <paramref name="pl2"/>
/// intersects the rectangle.
/// </summary>
private static PdfPoint[] Intersect(PdfRectangle rectangle, PdfPoint pl1, PdfPoint pl2)
{
var clipper = new Clipper();
clipper.AddPath(rectangle.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true);
clipper.AddPath(new List<ClipperIntPoint>() { pl1.ToClipperIntPoint(), pl2.ToClipperIntPoint() }, ClipperPolyType.Subject, false);
var solutions = new ClipperPolyTree();
if (clipper.Execute(ClipperClipType.Intersection, solutions))
{
if (solutions.Children.Count == 0)
{
return null;
}
else if (solutions.Children.Count == 1)
{
var solution = solutions.Children[0];
return new[]
{
new PdfPoint(solution.Contour[0].X / ClippingExtensions.Factor, solution.Contour[0].Y / ClippingExtensions.Factor),
new PdfPoint(solution.Contour[1].X / ClippingExtensions.Factor, solution.Contour[1].Y / ClippingExtensions.Factor)
};
}
else
{
throw new ArgumentException("GeometryExtensions.Intersect(PdfRectangle, PdfPoint, PdfPoint): more than one solution found.");
}
}
else
{
return null;
}
// clipper.clear() ??
}
/// <summary>
/// Whether the line formed by <paramref name="pl1"/> and <paramref name="pl2"/>
/// intersects the rectangle.
/// </summary>
public static bool IntersectsWith(PdfRectangle rectangle, PdfPoint pl1, PdfPoint pl2)
{
var clipper = new Clipper();
clipper.AddPath(rectangle.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true);
clipper.AddPath(new List<ClipperIntPoint>() { pl1.ToClipperIntPoint(), pl2.ToClipperIntPoint() }, ClipperPolyType.Subject, false);
var solutions = new ClipperPolyTree();
if (clipper.Execute(ClipperClipType.Intersection, solutions))
{
return solutions.Children.Count > 0;
}
return false;
}
private static bool ParallelTo(PdfPoint p11, PdfPoint p12, PdfPoint p21, PdfPoint p22)
{
return Math.Abs((p12.Y - p11.Y) * (p22.X - p21.X) - (p22.Y - p21.Y) * (p12.X - p11.X)) < epsilon;