Simplify PdfRectangle width and height computation and fix tests

This commit is contained in:
BobLd 2024-08-08 10:33:41 +01:00
parent a99c0d25bf
commit 56baa3592b
3 changed files with 60 additions and 70 deletions

View File

@ -11,32 +11,32 @@
/// The Y-axis extends vertically upwards and the X-axis horizontally to the right.
/// Unless otherwise specified on a per-page basis, units in PDF space are equivalent to a typographic point (1/72 inch).
/// </remarks>
public struct PdfRectangle
public readonly struct PdfRectangle
{
/// <summary>
/// Top left point of the rectangle.
/// </summary>
public readonly PdfPoint TopLeft { get; }
public PdfPoint TopLeft { get; }
/// <summary>
/// Top right point of the rectangle.
/// </summary>
public readonly PdfPoint TopRight { get; }
public PdfPoint TopRight { get; }
/// <summary>
/// Bottom right point of the rectangle.
/// </summary>
public readonly PdfPoint BottomRight { get; }
public PdfPoint BottomRight { get; }
/// <summary>
/// Bottom left point of the rectangle.
/// </summary>
public readonly PdfPoint BottomLeft { get; }
public PdfPoint BottomLeft { get; }
/// <summary>
/// Centroid point of the rectangle.
/// </summary>
public readonly PdfPoint Centroid
public PdfPoint Centroid
{
get
{
@ -46,47 +46,23 @@
}
}
private double width;
/// <summary>
/// Width of the rectangle.
/// <para>A positive number.</para>
/// </summary>
public double Width
{
get
{
if (double.IsNaN(width))
{
GetWidthHeight();
}
public double Width { get; }
return width;
}
}
private double height;
/// <summary>
/// Height of the rectangle.
/// <para>A positive number.</para>
/// </summary>
public double Height
{
get
{
if (double.IsNaN(height))
{
GetWidthHeight();
}
return height;
}
}
public double Height { get; }
/// <summary>
/// Rotation angle of the rectangle. Counterclockwise, in degrees.
/// <para>-180 ≤ θ ≤ 180</para>
/// </summary>
public readonly double Rotation => GetT() * 180 / Math.PI;
public double Rotation => GetT() * 180 / Math.PI;
/// <summary>
/// Area of the rectangle.
@ -96,22 +72,22 @@
/// <summary>
/// Left. This value is only valid if the rectangle is not rotated, check <see cref="Rotation"/>.
/// </summary>
public readonly double Left => TopLeft.X < TopRight.X ? TopLeft.X : TopRight.X;
public double Left => TopLeft.X < TopRight.X ? TopLeft.X : TopRight.X;
/// <summary>
/// Top. This value is only valid if the rectangle is not rotated, check <see cref="Rotation"/>.
/// </summary>
public readonly double Top => TopLeft.Y > BottomLeft.Y ? TopLeft.Y : BottomLeft.Y;
public double Top => TopLeft.Y > BottomLeft.Y ? TopLeft.Y : BottomLeft.Y;
/// <summary>
/// Right. This value is only valid if the rectangle is not rotated, check <see cref="Rotation"/>.
/// </summary>
public readonly double Right => BottomRight.X > BottomLeft.X ? BottomRight.X : BottomLeft.X;
public double Right => BottomRight.X > BottomLeft.X ? BottomRight.X : BottomLeft.X;
/// <summary>
/// Bottom. This value is only valid if the rectangle is not rotated, check <see cref="Rotation"/>.
/// </summary>
public readonly double Bottom => BottomRight.Y < TopRight.Y ? BottomRight.Y : TopRight.Y;
public double Bottom => BottomRight.Y < TopRight.Y ? BottomRight.Y : TopRight.Y;
/// <summary>
/// Create a new <see cref="PdfRectangle"/>.
@ -155,8 +131,8 @@
BottomLeft = bottomLeft;
BottomRight = bottomRight;
width = double.NaN;
height = double.NaN;
Width = Math.Sqrt((BottomLeft.X - BottomRight.X) * (BottomLeft.X - BottomRight.X) + (BottomLeft.Y - BottomRight.Y) * (BottomLeft.Y - BottomRight.Y));
Height = Math.Sqrt((BottomLeft.X - TopLeft.X) * (BottomLeft.X - TopLeft.X) + (BottomLeft.Y - TopLeft.Y) * (BottomLeft.Y - TopLeft.Y));
}
/// <summary>
@ -165,7 +141,7 @@
/// <param name="dx">The distance to move the rectangle in the x direction relative to its current location.</param>
/// <param name="dy">The distance to move the rectangle in the y direction relative to its current location.</param>
/// <returns>A new rectangle shifted on the y axis by the given delta value.</returns>
public readonly PdfRectangle Translate(double dx, double dy)
public PdfRectangle Translate(double dx, double dy)
{
return new PdfRectangle(TopLeft.Translate(dx, dy), TopRight.Translate(dx, dy),
BottomLeft.Translate(dx, dy), BottomRight.Translate(dx, dy));
@ -174,7 +150,7 @@
/// <summary>
/// -π ≤ θ ≤ π
/// </summary>
private readonly double GetT()
private double GetT()
{
if (!BottomRight.Equals(BottomLeft))
{
@ -185,24 +161,6 @@
return Math.Atan2(TopLeft.Y - BottomLeft.Y, TopLeft.X - BottomLeft.X) - Math.PI / 2;
}
private void GetWidthHeight()
{
var t = GetT();
var cos = Math.Cos(t);
var sin = Math.Sin(t);
var inverseRotation = new TransformationMatrix(
cos, -sin, 0,
sin, cos, 0,
0, 0, 1);
// Using Abs as a proxy for Euclidean distance in 1D
// as it might happen that points have negative coordinates.
var bl = inverseRotation.Transform(BottomLeft);
width = Math.Abs(inverseRotation.Transform(BottomRight).X - bl.X);
height = Math.Abs(inverseRotation.Transform(TopLeft).Y - bl.Y);
}
/// <inheritdoc />
public override string ToString()
{

View File

@ -64,10 +64,10 @@ namespace UglyToad.PdfPig.Tests.Fonts.SystemFonts
var current = page.Letters[i];
Assert.Equal(expectedData.TopLeft.X, current.GlyphRectangle.TopLeft.X, 7);
Assert.Equal(expectedData.TopLeft.Y, current.GlyphRectangle.TopLeft.Y, 7);
Assert.Equal(expectedData.Width, current.GlyphRectangle.Width, 7);
Assert.Equal(expectedData.Height, current.GlyphRectangle.Height, 7);
Assert.Equal(expectedData.TopLeft.X, current.GlyphRectangle.TopLeft.X, 6);
Assert.Equal(expectedData.TopLeft.Y, current.GlyphRectangle.TopLeft.Y, 6);
Assert.Equal(expectedData.Width, current.GlyphRectangle.Width, 6);
Assert.Equal(expectedData.Height, current.GlyphRectangle.Height, 6);
Assert.Equal(expectedData.Rotation, current.GlyphRectangle.Rotation, 3);
}
}

View File

@ -3,12 +3,11 @@
using Content;
using PdfPig.Geometry;
using PdfPig.Core;
using System.Drawing;
public class PdfRectangleTests
{
private static readonly DoubleComparer DoubleComparer = new DoubleComparer(3);
private static readonly DoubleComparer PreciseDoubleComparer = new DoubleComparer(6);
private static readonly DoubleComparer DoubleComparer = new DoubleComparer(0.001);
private static readonly DoubleComparer PreciseDoubleComparer = new DoubleComparer(0.000001);
private static readonly PointComparer PointComparer = new PointComparer(DoubleComparer);
private static readonly PdfRectangle UnitRectangle = new PdfRectangle(new PdfPoint(0, 0), new PdfPoint(1, 1));
@ -1460,6 +1459,11 @@
new PdfPoint(79.72935886126837, 162.40175959739133),
new PdfPoint(36.31110596050322, 137.33421959739135),
new PdfPoint(61.57811596050321, 93.57047452204044)
},
new double[]
{
50.135079999999988, // width
50.53402 // height
}
},
new object[]
@ -1475,6 +1479,11 @@
new PdfPoint(355.93382538513987, -509.2927859424674),
new PdfPoint(291.2932316380764, -201.33455131845915),
new PdfPoint(123.95226520870021, -236.45950727688313)
},
new double[]
{
314.66916060000005,
170.98760649999997
}
},
new object[]
@ -1490,6 +1499,11 @@
new PdfPoint(748.3932365836752, 221.98391118471883),
new PdfPoint(-70.46470122718794, 247.50297212341658),
new PdfPoint(-79.61250178788342, -46.03248047926875)
},
new double[]
{
819.255482,
293.67796
}
},
new object[]
@ -1505,6 +1519,11 @@
new PdfPoint(-62.47760759065051, 323.00991498515555),
new PdfPoint(227.9582036948802, 613.4457262706862),
new PdfPoint(-120.22754499429334, 961.6314749598598)
},
new double[]
{
410.73826331883026,
492.4090080212593
}
},
new object[]
@ -1520,6 +1539,11 @@
new PdfPoint(956.4918489990248, 290.16467735562713),
new PdfPoint(1243.8589223186318, 2.797604036020175),
new PdfPoint(1163.8416408097196, -77.21967747289204)
},
new double[]
{
406.39841246805167,
113.16152473412956
}
}
};
@ -1646,7 +1670,7 @@
Assert.Equal(new PdfPoint(-1, 1), rotated.TopRight);
Assert.Equal(1, rotated.Width, PreciseDoubleComparer);
Assert.Equal(-1, rotated.Height, PreciseDoubleComparer);
Assert.Equal(1, rotated.Height, PreciseDoubleComparer);
Assert.Equal(90, rotated.Rotation, PreciseDoubleComparer);
}
@ -1662,20 +1686,28 @@
Assert.Equal(new PdfPoint(0, -1), rotated.TopLeft);
Assert.Equal(new PdfPoint(-1, -1), rotated.TopRight);
Assert.Equal(-1, rotated.Width, PreciseDoubleComparer);
Assert.Equal(-1, rotated.Height, PreciseDoubleComparer);
Assert.Equal(1, rotated.Width, PreciseDoubleComparer);
Assert.Equal(1, rotated.Height, PreciseDoubleComparer);
Assert.Equal(180, rotated.Rotation, PreciseDoubleComparer);
}
[Theory]
[MemberData(nameof(RotateData))]
public void Rotate(double[][] data, PdfPoint[] expected)
public void Rotate(double[][] data, PdfPoint[] expected, double[] expectedSize)
{
var points = data[0];
var angle = data[1][0];
double width = expectedSize[0];
double height = expectedSize[1];
var rect = new PdfRectangle(points[0], points[1], points[2], points[3]);
Assert.Equal(width, rect.Width, PreciseDoubleComparer);
Assert.Equal(height, rect.Height, PreciseDoubleComparer);
var rectR = TransformationMatrix.GetRotationMatrix(angle).Transform(rect);
Assert.Equal(width, rectR.Width, PreciseDoubleComparer);
Assert.Equal(height, rectR.Height, PreciseDoubleComparer);
Assert.Equal(expected[0], rectR.BottomRight, PointComparer);
Assert.Equal(expected[1], rectR.TopRight, PointComparer);