swf2ass/src/MatrixTransform.php

147 lines
4.9 KiB
PHP

<?php
namespace swf2ass;
use MathPHP\LinearAlgebra\MatrixFactory;
use swf2ass\math\RealNumber;
use swf2ass\math\RealMatrix;
class MatrixTransform {
private RealMatrix $matrix;
public function __construct(?Vector2 $scale, ?Vector2 $rotateSkew, ?Vector2 $translation) {
$this->matrix = new RealMatrix([
[$scale !== null ? $scale->x : 1 /* a */, /* c */ $rotateSkew !== null ? $rotateSkew->y : 0, 0],
[$rotateSkew !== null ? $rotateSkew->x : 0 /* b */, /* d */ $scale !== null ? $scale->y : 1, 0],
[$translation !== null ? $translation->x : 0, $translation !== null ? $translation->y : 0, 1]
]);
}
public static function fromMatrix(RealMatrix $matrix) : MatrixTransform{
$o = new MatrixTransform(null, null, null);
$o->matrix = $matrix;
return $o;
}
public static function fromArray(array $array) : MatrixTransform{
return new MatrixTransform(new Vector2($array[0][0], $array[1][1]), new Vector2($array[1][0], $array[0][1]), new Vector2($array[0][2], $array[1][2]));
}
public function toArray(bool $translation = true) : array{
if($translation){
return [
[$this->get_a()->toFixed(), $this->get_b()->toFixed(), 0],
[$this->get_c()->toFixed(), $this->get_d()->toFixed(), 0],
[$this->get_tx()->toFixed(), $this->get_ty()->toFixed(), 1]
];
}else{
return [
[$this->get_a()->toFixed(), $this->get_b()->toFixed(), 0],
[$this->get_c()->toFixed(), $this->get_d()->toFixed(), 0],
[0, 0, 1]
];
}
}
public static function scale(Vector2 $scale) : MatrixTransform{
return new MatrixTransform($scale, null, null);
}
//TODO: check sin sign location
public static function rotate(float $angle) : MatrixTransform{
$cos = cos($angle);
$sin = sin($angle);
return new MatrixTransform(new Vector2($cos, $cos), new Vector2(-$sin, $sin), null);
}
public static function translate(Vector2 $translation) : MatrixTransform{
return new MatrixTransform(null, null, $translation);
}
public static function identity(): MatrixTransform {
return new MatrixTransform(null, null, null);
}
public static function skewX(float $angle) : MatrixTransform{
return new MatrixTransform(null, new Vector2(tan($angle), 0), null);
}
public static function skewY(float $angle) : MatrixTransform{
return new MatrixTransform(null, new Vector2(0, tan($angle)), null);
}
public function multiply(MatrixTransform $other): MatrixTransform {
$result = clone $this;
$result->matrix = $this->matrix->multiply($other->matrix);
return $result;
}
public function get_a() : RealNumber{
return $this->matrix->get(0, 0);
}
public function get_b() : RealNumber{
return $this->matrix->get(1, 0);
}
public function get_c() : RealNumber{
return $this->matrix->get(0, 1);
}
public function get_d() : RealNumber{
return $this->matrix->get(1, 1);
}
public function get_tx() : RealNumber{
return $this->matrix->get(0, 2);
}
public function get_ty() : RealNumber{
return $this->matrix->get(1, 2);
}
public function getMatrix() : RealMatrix{
return $this->matrix;
}
public function getTranslation(): Vector2 {
return $this->applyToVector(new Vector2(0, 0));
}
public function applyToVector(Vector2 $vector, bool $applyTranslation = true): Vector2 {
if($applyTranslation){
$result = (new RealMatrix([[$vector->x, $vector->y, 1]]))->multiply($this->matrix);
}else{
$result = (new RealMatrix([[$vector->x, $vector->y]]))->multiply($this->matrix->submatrix(0, 0, 1, 1));
}
return new Vector2($result->get(0, 0)->toFloat(), $result->get(0, 1)->toFloat());
}
public function applyToShape(Shape $shape, bool $applyTranslation = true): Shape {
$newShape = new Shape();
foreach ($shape->getRecords() as $edge) {
$newShape->addRecord($edge->applyMatrixTransform($this, $applyTranslation));
}
return $newShape;
}
public function equals(MatrixTransform $other): bool {
return $this->matrix->isEqual($other->matrix, new RealNumber(0.0001));
}
static function fromSWFArray(array $element): MatrixTransform {
return new MatrixTransform(
isset($element["scaleX"]) ? new Vector2($element["scaleX"], $element["scaleY"]) : null,
isset($element["rotateSkew0"]) ? new Vector2($element["rotateSkew1"], $element["rotateSkew0"]) : null,
isset($element["translateX"]) ? new Vector2($element["translateX"], $element["translateY"]) : null
);
}
public function __toString() : string{
return (string) $this->matrix;
}
}