From 56baa3592b5b2cdd2e3d82b474ebfbcf4775206f Mon Sep 17 00:00:00 2001
From: BobLd <38405645+BobLd@users.noreply.github.com>
Date: Thu, 8 Aug 2024 10:33:41 +0100
Subject: [PATCH] Simplify PdfRectangle width and height computation and fix
tests
---
src/UglyToad.PdfPig.Core/PdfRectangle.cs | 76 +++++--------------
.../Fonts/SystemFonts/Linux.cs | 8 +-
.../Geometry/PdfRectangleTests.cs | 46 +++++++++--
3 files changed, 60 insertions(+), 70 deletions(-)
diff --git a/src/UglyToad.PdfPig.Core/PdfRectangle.cs b/src/UglyToad.PdfPig.Core/PdfRectangle.cs
index f5661b50..dd500b4e 100644
--- a/src/UglyToad.PdfPig.Core/PdfRectangle.cs
+++ b/src/UglyToad.PdfPig.Core/PdfRectangle.cs
@@ -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).
///
- public struct PdfRectangle
+ public readonly struct PdfRectangle
{
///
/// Top left point of the rectangle.
///
- public readonly PdfPoint TopLeft { get; }
+ public PdfPoint TopLeft { get; }
///
/// Top right point of the rectangle.
///
- public readonly PdfPoint TopRight { get; }
+ public PdfPoint TopRight { get; }
///
/// Bottom right point of the rectangle.
///
- public readonly PdfPoint BottomRight { get; }
+ public PdfPoint BottomRight { get; }
///
/// Bottom left point of the rectangle.
///
- public readonly PdfPoint BottomLeft { get; }
+ public PdfPoint BottomLeft { get; }
///
/// Centroid point of the rectangle.
///
- public readonly PdfPoint Centroid
+ public PdfPoint Centroid
{
get
{
@@ -46,47 +46,23 @@
}
}
- private double width;
///
/// Width of the rectangle.
/// A positive number.
///
- public double Width
- {
- get
- {
- if (double.IsNaN(width))
- {
- GetWidthHeight();
- }
+ public double Width { get; }
- return width;
- }
- }
-
- private double height;
///
/// Height of the rectangle.
/// A positive number.
///
- public double Height
- {
- get
- {
- if (double.IsNaN(height))
- {
- GetWidthHeight();
- }
-
- return height;
- }
- }
+ public double Height { get; }
///
/// Rotation angle of the rectangle. Counterclockwise, in degrees.
/// -180 ≤ θ ≤ 180
///
- public readonly double Rotation => GetT() * 180 / Math.PI;
+ public double Rotation => GetT() * 180 / Math.PI;
///
/// Area of the rectangle.
@@ -96,22 +72,22 @@
///
/// Left. This value is only valid if the rectangle is not rotated, check .
///
- public readonly double Left => TopLeft.X < TopRight.X ? TopLeft.X : TopRight.X;
+ public double Left => TopLeft.X < TopRight.X ? TopLeft.X : TopRight.X;
///
/// Top. This value is only valid if the rectangle is not rotated, check .
///
- public readonly double Top => TopLeft.Y > BottomLeft.Y ? TopLeft.Y : BottomLeft.Y;
+ public double Top => TopLeft.Y > BottomLeft.Y ? TopLeft.Y : BottomLeft.Y;
///
/// Right. This value is only valid if the rectangle is not rotated, check .
///
- public readonly double Right => BottomRight.X > BottomLeft.X ? BottomRight.X : BottomLeft.X;
+ public double Right => BottomRight.X > BottomLeft.X ? BottomRight.X : BottomLeft.X;
///
/// Bottom. This value is only valid if the rectangle is not rotated, check .
///
- public readonly double Bottom => BottomRight.Y < TopRight.Y ? BottomRight.Y : TopRight.Y;
+ public double Bottom => BottomRight.Y < TopRight.Y ? BottomRight.Y : TopRight.Y;
///
/// Create a new .
@@ -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));
}
///
@@ -165,7 +141,7 @@
/// The distance to move the rectangle in the x direction relative to its current location.
/// The distance to move the rectangle in the y direction relative to its current location.
/// A new rectangle shifted on the y axis by the given delta value.
- 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 @@
///
/// -π ≤ θ ≤ π
///
- 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);
- }
-
///
public override string ToString()
{
diff --git a/src/UglyToad.PdfPig.Tests/Fonts/SystemFonts/Linux.cs b/src/UglyToad.PdfPig.Tests/Fonts/SystemFonts/Linux.cs
index ecd4c305..0906c8d4 100644
--- a/src/UglyToad.PdfPig.Tests/Fonts/SystemFonts/Linux.cs
+++ b/src/UglyToad.PdfPig.Tests/Fonts/SystemFonts/Linux.cs
@@ -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);
}
}
diff --git a/src/UglyToad.PdfPig.Tests/Geometry/PdfRectangleTests.cs b/src/UglyToad.PdfPig.Tests/Geometry/PdfRectangleTests.cs
index 40364341..db728b30 100644
--- a/src/UglyToad.PdfPig.Tests/Geometry/PdfRectangleTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Geometry/PdfRectangleTests.cs
@@ -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);