2018-01-11 03:49:32 +08:00
namespace UglyToad.PdfPig.Core
2017-11-23 02:41:34 +08:00
{
using System ;
2017-12-01 07:49:53 +08:00
using System.Collections.Generic ;
2018-01-07 04:51:20 +08:00
using System.Diagnostics.Contracts ;
2018-01-11 03:49:32 +08:00
using Geometry ;
2017-11-23 02:41:34 +08:00
/// <summary>
/// Specifies the conversion from the transformed coordinate space to the original untransformed coordinate space.
/// </summary>
internal struct TransformationMatrix
{
2017-11-30 06:55:53 +08:00
public static TransformationMatrix Identity = new TransformationMatrix ( new decimal [ ]
2017-11-23 02:41:34 +08:00
{
1 , 0 , 0 ,
0 , 1 , 0 ,
0 , 0 , 1
} ) ;
private readonly decimal [ ] value ;
2017-12-29 00:58:52 +08:00
/// <summary>
/// The scale for the X dimension.
/// </summary>
2017-11-23 02:41:34 +08:00
public decimal A = > value [ 0 ] ;
public decimal B = > value [ 1 ] ;
public decimal C = > value [ 3 ] ;
2017-12-29 00:58:52 +08:00
/// <summary>
/// The scale for the Y dimension.
/// </summary>
2017-11-23 02:41:34 +08:00
public decimal D = > value [ 4 ] ;
public decimal E = > value [ 6 ] ;
public decimal F = > value [ 7 ] ;
2017-11-30 06:55:53 +08:00
public decimal this [ int row , int col ]
{
get
{
if ( row > = Rows )
{
throw new ArgumentOutOfRangeException ( $"The transformation matrix only contains {Rows} rows and is zero indexed, you tried to access row {row}." ) ;
}
if ( row < 0 )
{
throw new ArgumentOutOfRangeException ( "Cannot access negative rows in a matrix." ) ;
}
if ( col > = Columns )
{
throw new ArgumentOutOfRangeException ( $"The transformation matrix only contains {Columns} columns and is zero indexed, you tried to access column {col}." ) ;
}
if ( col < 0 )
{
throw new ArgumentOutOfRangeException ( "Cannot access negative columns in a matrix." ) ;
}
var resultIndex = row * Rows + col ;
if ( resultIndex > value . Length - 1 )
{
throw new ArgumentOutOfRangeException ( $"Trying to access {row}, {col} mapped to the index {resultIndex} which was not in the value array." ) ;
}
return value [ resultIndex ] ;
}
}
public const int Rows = 3 ;
public const int Columns = 3 ;
2017-11-23 02:41:34 +08:00
public TransformationMatrix ( decimal [ ] value )
{
if ( value = = null )
{
throw new ArgumentNullException ( nameof ( value ) ) ;
}
if ( value . Length ! = 9 )
{
throw new ArgumentException ( "The constructor for the PDF transformation matrix must contain 9 elements. Instead got: " + value ) ;
}
this . value = value ;
}
public PdfPoint Transform ( PdfPoint original )
{
var x = A * original . X + C * original . Y + E ;
var y = B * original . X + D * original . Y + F ;
return new PdfPoint ( x , y ) ;
}
2017-12-01 07:34:38 +08:00
2018-01-07 04:51:20 +08:00
[Pure]
public PdfVector Transform ( PdfVector original )
{
var x = A * original . X + C * original . Y + E ;
var y = B * original . X + D * original . Y + F ;
return new PdfVector ( x , y ) ;
}
2018-03-31 06:16:54 +08:00
[Pure]
public PdfRectangle Transform ( PdfRectangle original )
{
return new PdfRectangle (
2018-04-12 06:18:24 +08:00
Transform ( original . TopLeft . ToVector ( ) ) ,
Transform ( original . TopRight . ToVector ( ) ) ,
2018-03-31 06:16:54 +08:00
Transform ( original . BottomLeft . ToVector ( ) ) ,
2018-04-12 06:18:24 +08:00
Transform ( original . BottomRight . ToVector ( ) )
2018-03-31 06:16:54 +08:00
) ;
}
2017-12-01 07:34:38 +08:00
public static TransformationMatrix FromValues ( decimal a , decimal b , decimal c , decimal d , decimal e , decimal f )
= > FromArray ( new [ ] { a , b , c , d , e , f } ) ;
public static TransformationMatrix FromArray ( decimal [ ] values )
2017-11-23 02:41:34 +08:00
{
if ( values . Length = = 9 )
{
return new TransformationMatrix ( values ) ;
}
if ( values . Length = = 6 )
{
return new TransformationMatrix ( new [ ]
{
values [ 0 ] , values [ 1 ] , 0 ,
values [ 2 ] , values [ 3 ] , 0 ,
values [ 4 ] , values [ 5 ] , 1
} ) ;
}
throw new ArgumentException ( "The array must either define all 9 elements of the matrix or all 6 key elements. Instead array was: " + values ) ;
}
2017-11-30 06:55:53 +08:00
public TransformationMatrix Multiply ( TransformationMatrix matrix )
{
var result = new decimal [ 9 ] ;
for ( int i = 0 ; i < Rows ; i + + )
{
for ( int j = 0 ; j < Columns ; j + + )
{
var index = ( i * Rows ) + j ;
for ( int x = 0 ; x < Rows ; x + + )
{
result [ index ] + = this [ i , x ] * matrix [ x , j ] ;
}
}
}
return new TransformationMatrix ( result ) ;
}
2018-03-31 06:16:54 +08:00
public TransformationMatrix Multiply ( decimal scalar )
{
var result = new decimal [ 9 ] ;
for ( int i = 0 ; i < Rows ; i + + )
{
for ( int j = 0 ; j < Columns ; j + + )
{
var index = ( i * Rows ) + j ;
for ( int x = 0 ; x < Rows ; x + + )
{
result [ index ] + = this [ i , x ] * scalar ;
}
}
}
return new TransformationMatrix ( result ) ;
}
2018-01-03 06:23:08 +08:00
public decimal GetScalingFactorX ( )
{
var xScale = A ;
2018-01-07 20:37:48 +08:00
/ *
2018-01-03 06:23:08 +08:00
* BM : if the trm is rotated , the calculation is a little more complicated
*
* The rotation matrix multiplied with the scaling matrix is :
* ( x 0 0 ) ( cos sin 0 ) ( x * cos x * sin 0 )
* ( 0 y 0 ) * ( - sin cos 0 ) = ( - y * sin y * cos 0 )
* ( 0 0 1 ) ( 0 0 1 ) ( 0 0 1 )
*
* So , if you want to deduce x from the matrix you take
* M ( 0 , 0 ) = x * cos and M ( 0 , 1 ) = x * sin and use the theorem of Pythagoras
*
* sqrt ( M ( 0 , 0 ) ^ 2 + M ( 0 , 1 ) ^ 2 ) =
* sqrt ( x2 * cos2 + x2 * sin2 ) =
2018-01-07 20:37:48 +08:00
* sqrt ( x2 * ( cos2 + sin2 ) ) = ( here is the trick cos2 + sin2 = 1 )
2018-01-03 06:23:08 +08:00
* sqrt ( x2 ) =
* abs ( x )
* /
if ( ! ( B = = 0 m & & C = = 0 m ) )
{
xScale = ( decimal ) Math . Sqrt ( ( double ) ( A * A + B * B ) ) ;
}
return xScale ;
}
2017-11-30 06:55:53 +08:00
public override bool Equals ( object obj )
{
if ( ! ( obj is TransformationMatrix m ) )
{
return false ;
}
return Equals ( this , m ) ;
}
public static bool Equals ( TransformationMatrix a , TransformationMatrix b )
{
for ( int i = 0 ; i < Rows ; i + + )
{
for ( int j = 0 ; j < Columns ; j + + )
{
if ( a [ i , j ] ! = b [ i , j ] )
{
return false ;
}
}
}
return true ;
}
2017-12-01 07:49:53 +08:00
public override int GetHashCode ( )
{
var hashCode = 1113510858 ;
hashCode = hashCode * - 1521134295 + base . GetHashCode ( ) ;
hashCode = hashCode * - 1521134295 + EqualityComparer < decimal [ ] > . Default . GetHashCode ( value ) ;
return hashCode ;
}
2017-11-23 02:41:34 +08:00
public override string ToString ( )
{
return $"{A}, {B}, 0\r\n{C}, {D}, 0\r\n{E}, {F}, 1" ;
}
2017-12-02 22:57:44 +08:00
public static TransformationMatrix GetTranslationMatrix ( decimal x , decimal y )
{
return new TransformationMatrix ( new [ ]
{
1 , 0 , 0 ,
0 , 1 , 0 ,
x , y , 1
} ) ;
}
2017-11-23 02:41:34 +08:00
}
}