mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
Simplify PdfRectangle width and height computation and fix tests
This commit is contained in:
parent
a99c0d25bf
commit
56baa3592b
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user