371 lines
11 KiB
PHP
371 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Transform.php
|
|
*
|
|
* @since 2011-05-23
|
|
* @category Library
|
|
* @package PdfGraph
|
|
* @author Nicola Asuni <info@tecnick.com>
|
|
* @copyright 2011-2024 Nicola Asuni - Tecnick.com LTD
|
|
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
|
|
* @link https://github.com/tecnickcom/tc-lib-pdf-graph
|
|
*
|
|
* This file is part of tc-lib-pdf-graph software library.
|
|
*/
|
|
|
|
namespace Com\Tecnick\Pdf\Graph;
|
|
|
|
use Com\Tecnick\Pdf\Graph\Exception as GraphException;
|
|
|
|
/**
|
|
* Com\Tecnick\Pdf\Graph\Transform
|
|
*
|
|
* @since 2011-05-23
|
|
* @category Library
|
|
* @package PdfGraph
|
|
* @author Nicola Asuni <info@tecnick.com>
|
|
* @copyright 2011-2024 Nicola Asuni - Tecnick.com LTD
|
|
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
|
|
* @link https://github.com/tecnickcom/tc-lib-pdf-graph
|
|
*
|
|
* @phpstan-import-type TTMatrix from \Com\Tecnick\Pdf\Graph\Base
|
|
*/
|
|
abstract class Transform extends \Com\Tecnick\Pdf\Graph\Style
|
|
{
|
|
/**
|
|
* Current ID for transformation matrix.
|
|
*/
|
|
protected int $ctmid = -1;
|
|
|
|
/**
|
|
* Array (stack) of Current Transformation Matrix (CTM),
|
|
* which maps user space coordinates used within a PDF content stream into output device coordinates.
|
|
*
|
|
* @var array<int, array<int, TTMatrix>>
|
|
*/
|
|
protected array $ctm = [];
|
|
|
|
/**
|
|
* Returns the transformation stack.
|
|
*
|
|
* @return array<int, array<int, TTMatrix>>
|
|
*/
|
|
public function getTransformStack(): array
|
|
{
|
|
return $this->ctm;
|
|
}
|
|
|
|
/**
|
|
* Returns the transformation stack index.
|
|
*/
|
|
public function getTransformIndex(): int
|
|
{
|
|
return $this->ctmid;
|
|
}
|
|
|
|
/**
|
|
* Starts a 2D transformation saving current graphic state.
|
|
* This function must be called before calling transformation methods
|
|
*/
|
|
public function getStartTransform(): string
|
|
{
|
|
$this->saveStyleStatus();
|
|
$this->ctm[++$this->ctmid] = [];
|
|
return 'q' . "\n";
|
|
}
|
|
|
|
/**
|
|
* Stops a 2D tranformation restoring previous graphic state.
|
|
* This function must be called after calling transformation methods.
|
|
*/
|
|
public function getStopTransform(): string
|
|
{
|
|
if (! isset($this->ctm[$this->ctmid])) {
|
|
return '';
|
|
}
|
|
|
|
unset($this->ctm[$this->ctmid]);
|
|
--$this->ctmid;
|
|
$this->restoreStyleStatus();
|
|
return 'Q' . "\n";
|
|
}
|
|
|
|
/**
|
|
* Get the tranformation matrix (CTM) PDF string
|
|
*
|
|
* @param TTMatrix $ctm Transformation matrix array.
|
|
*/
|
|
public function getTransformation(array $ctm): string
|
|
{
|
|
$this->ctm[$this->ctmid][] = $ctm;
|
|
return sprintf('%F %F %F %F %F %F cm' . "\n", $ctm[0], $ctm[1], $ctm[2], $ctm[3], $ctm[4], $ctm[5]);
|
|
}
|
|
|
|
/**
|
|
* Vertical and horizontal non-proportional Scaling.
|
|
*
|
|
* @param float $skx Horizontal scaling factor.
|
|
* @param float $sky vertical scaling factor.
|
|
* @param float $posx Abscissa of the scaling center.
|
|
* @param float $posy Ordinate of the scaling center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getScaling(float $skx, float $sky, float $posx, float $posy): string
|
|
{
|
|
if (($skx == 0) || ($sky == 0)) {
|
|
throw new GraphException('Scaling factors must be different than zero');
|
|
}
|
|
|
|
$posy = (($this->pageh - $posy) * $this->kunit);
|
|
$posx *= $this->kunit;
|
|
$ctm = [$skx, 0, 0, $sky, ($posx * (1 - $skx)), ($posy * (1 - $sky))];
|
|
return $this->getTransformation($ctm);
|
|
}
|
|
|
|
/**
|
|
* Horizontal Scaling.
|
|
*
|
|
* @param float $skx Horizontal scaling factor.
|
|
* @param float $posx Abscissa of the scaling center.
|
|
* @param float $posy Ordinate of the scaling center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getHorizScaling(float $skx, float $posx, float $posy): string
|
|
{
|
|
return $this->getScaling($skx, 1, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Vertical Scaling.
|
|
*
|
|
* @param float $sky vertical scaling factor.
|
|
* @param float $posx Abscissa of the scaling center.
|
|
* @param float $posy Ordinate of the scaling center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getVertScaling(float $sky, float $posx, float $posy): string
|
|
{
|
|
return $this->getScaling(1, $sky, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Vertical and horizontal proportional Scaling.
|
|
*
|
|
* @param float $skf Scaling factor.
|
|
* @param float $posx Abscissa of the scaling center.
|
|
* @param float $posy Ordinate of the scaling center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getPropScaling(float $skf, float $posx, float $posy): string
|
|
{
|
|
return $this->getScaling($skf, $skf, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Rotation.
|
|
*
|
|
* @param float $angle Angle in degrees for counter-clockwise rotation.
|
|
* @param float $posx Abscissa of the rotation center.
|
|
* @param float $posy Ordinate of the rotation center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getRotation(float $angle, float $posx, float $posy): string
|
|
{
|
|
$posy = (($this->pageh - $posy) * $this->kunit);
|
|
$posx *= $this->kunit;
|
|
$ctm = [];
|
|
$ctm[0] = cos($this->degToRad($angle));
|
|
$ctm[1] = sin($this->degToRad($angle));
|
|
$ctm[2] = -$ctm[1];
|
|
$ctm[3] = $ctm[0];
|
|
$ctm[4] = ($posx + ($ctm[1] * $posy) - ($ctm[0] * $posx));
|
|
$ctm[5] = ($posy - ($ctm[0] * $posy) - ($ctm[1] * $posx));
|
|
return $this->getTransformation($ctm);
|
|
}
|
|
|
|
/**
|
|
* Horizontal Mirroring.
|
|
*
|
|
* @param float $posx Abscissa of the mirroring line.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getHorizMirroring(float $posx): string
|
|
{
|
|
return $this->getScaling(-1, 1, $posx, 0);
|
|
}
|
|
|
|
/**
|
|
* Verical Mirroring.
|
|
*
|
|
* @param float $posy Ordinate of the mirroring line.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getVertMirroring(float $posy): string
|
|
{
|
|
return $this->getScaling(1, -1, 0, $posy);
|
|
}
|
|
|
|
/**
|
|
* Point reflection mirroring.
|
|
*
|
|
* @param float $posx Abscissa of the mirroring point.
|
|
* @param float $posy Ordinate of the mirroring point.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getPointMirroring(float $posx, float $posy): string
|
|
{
|
|
return $this->getScaling(-1, -1, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Reflection against a straight line through point (x, y) with the gradient angle (angle).
|
|
*
|
|
* @param float $ang Gradient angle in degrees of the straight line.
|
|
* @param float $posx Abscissa of the mirroring point.
|
|
* @param float $posy Ordinate of the mirroring point.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getReflection(float $ang, float $posx, float $posy): string
|
|
{
|
|
return $this->getScaling(-1, 1, $posx, $posy) . $this->getRotation((-2 * ($ang - 90)), $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Translate graphic object horizontally and vertically.
|
|
*
|
|
* @param float $trx Movement to the right.
|
|
* @param float $try Movement to the bottom.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getTranslation(float $trx, float $try): string
|
|
{
|
|
//calculate elements of transformation matrix
|
|
$ctm = [1, 0, 0, 1, ($trx * $this->kunit), (-$try * $this->kunit)];
|
|
return $this->getTransformation($ctm);
|
|
}
|
|
|
|
/**
|
|
* Translate graphic object horizontally.
|
|
*
|
|
* @param float $trx Movement to the right.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getHorizTranslation(float $trx): string
|
|
{
|
|
return $this->getTranslation($trx, 0);
|
|
}
|
|
|
|
/**
|
|
* Translate graphic object vertically.
|
|
*
|
|
* @param float $try Movement to the bottom.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getVertTranslation(float $try): string
|
|
{
|
|
return $this->getTranslation(0, $try);
|
|
}
|
|
|
|
/**
|
|
* Skew.
|
|
*
|
|
* @param float $angx Angle in degrees between -90 (skew to the left) and 90 (skew to the right)
|
|
* @param float $angy Angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
|
|
* @param float $posx Abscissa of the skewing center.
|
|
* @param float $posy Ordinate of the skewing center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getSkewing(float $angx, float $angy, float $posx, float $posy): string
|
|
{
|
|
if (($angx <= -90) || ($angx >= 90) || ($angy <= -90) || ($angy >= 90)) {
|
|
throw new GraphException('Angle values must be beweeen -90 and +90 degrees.');
|
|
}
|
|
|
|
$posy = (($this->pageh - $posy) * $this->kunit);
|
|
$posx *= $this->kunit;
|
|
$ctm = [];
|
|
$ctm[0] = 1;
|
|
$ctm[1] = tan($this->degToRad($angy));
|
|
$ctm[2] = tan($this->degToRad($angx));
|
|
$ctm[3] = 1;
|
|
$ctm[4] = (-$ctm[2] * $posy);
|
|
$ctm[5] = (-$ctm[1] * $posx);
|
|
return $this->getTransformation($ctm);
|
|
}
|
|
|
|
/**
|
|
* Skew horizontally.
|
|
*
|
|
* @param float $angx Angle in degrees between -90 (skew to the left) and 90 (skew to the right)
|
|
* @param float $posx Abscissa of the skewing center.
|
|
* @param float $posy Ordinate of the skewing center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getHorizSkewing(float $angx, float $posx, float $posy): string
|
|
{
|
|
return $this->getSkewing($angx, 0, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Skew vertically.
|
|
*
|
|
* @param float $angy Angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
|
|
* @param float $posx Abscissa of the skewing center.
|
|
* @param float $posy Ordinate of the skewing center.
|
|
*
|
|
* @return string Transformation string
|
|
*/
|
|
public function getVertSkewing(float $angy, float $posx, float $posy): string
|
|
{
|
|
return $this->getSkewing(0, $angy, $posx, $posy);
|
|
}
|
|
|
|
/**
|
|
* Get the product of two Tranformation Matrix.
|
|
*
|
|
* @param TTMatrix $tma First Tranformation Matrix.
|
|
* @param TTMatrix $tmb Second Tranformation Matrix.
|
|
*
|
|
* @return TTMatrix CTM Transformation Matrix.
|
|
*/
|
|
public function getCtmProduct(array $tma, array $tmb): array
|
|
{
|
|
return [
|
|
(($tma[0] * $tmb[0]) + ($tma[2] * $tmb[1])),
|
|
(($tma[1] * $tmb[0]) + ($tma[3] * $tmb[1])),
|
|
(($tma[0] * $tmb[2]) + ($tma[2] * $tmb[3])),
|
|
(($tma[1] * $tmb[2]) + ($tma[3] * $tmb[3])),
|
|
(($tma[0] * $tmb[4]) + ($tma[2] * $tmb[5]) + $tma[4]),
|
|
(($tma[1] * $tmb[4]) + ($tma[3] * $tmb[5]) + $tma[5]),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Converts the number in degrees to the radian equivalent.
|
|
* We use this instead of $this->degToRad to avoid precision problems with hhvm.
|
|
*
|
|
* @param float $deg Angular value in degrees.
|
|
*
|
|
* @return float Angle in radiants
|
|
*/
|
|
public function degToRad(float $deg): float
|
|
{
|
|
return ($deg * self::MPI / 180);
|
|
}
|
|
}
|