swf2ass/src/MatrixTransform.php

140 lines
4.5 KiB
PHP

<?php
namespace swf2ass;
class MatrixTransform {
private const IDENTITY = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
private Matrix2D $matrix;
public function __construct(?Vector2 $scale, ?Vector2 $rotateSkew, ?Vector2 $translation) {
$matrix = self::IDENTITY;
if ($scale !== null) {
$matrix[0][0] = $scale->x;
$matrix[1][1] = $scale->y;
}
if ($rotateSkew !== null) {
$matrix[1][0] = $rotateSkew->x;
$matrix[0][1] = $rotateSkew->y;
}
if ($translation !== null) {
$matrix[2][0] = $translation->x;
$matrix[2][1] = $translation->y;
}
$this->matrix = Matrix2D::from2DArray($matrix);
}
public static function identity(): MatrixTransform {
return new MatrixTransform(new Vector2(1, 1), new Vector2(0, 0), new Vector2(0, 0));
}
public function combine(MatrixTransform $other): MatrixTransform {
$result = clone $this;
$result->matrix = $this->matrix->product($other->matrix);
return $result;
}
public function getScaleX() {
return $this->matrix->get(new Vector2(0, 0));
}
public function getScaleY() {
return $this->matrix->get(new Vector2(1, 1));
}
public function getScale(): Vector2 {
return new Vector2($this->getScaleX(), $this->getScaleY());
}
public function getRotateSkewX() {
return $this->matrix->get(new Vector2(0, 1));
}
public function getRotateSkewY() {
return $this->matrix->get(new Vector2(1, 0));
}
public function getRotateSkew(): Vector2 {
return new Vector2($this->getRotateSkewX(), $this->getRotateSkewY());
}
public function getTranslationX() {
return $this->matrix->get(new Vector2(0, 2));
}
public function getTranslationY() {
return $this->matrix->get(new Vector2(1, 2));
}
public function getTranslation(): Vector2 {
return new Vector2($this->getTranslationX(), $this->getTranslationY());
}
public function applyToVector(Vector2 $vector): Vector2 {
$result = Matrix2D::from2DArray([[$vector->x, $vector->y, 1]])->product($this->matrix);
return new Vector2($result->get(new Vector2(0, 0)), $result->get(new Vector2(1, 0)));
/*
return
$vector->vectorMultiply($this->getScale()) //scale
->add($vector->vectorMultiply($this->getRotateSkew())->invert()) //skew
->add($this->getTranslation()); //translate
*/
}
public function applyToShape(Shape $shape): Shape {
$newShape = new Shape();
foreach ($shape->edges as $edge) {
$newShape->edges[] = $edge->applyMatrixTransform($this);
}
return $newShape;
}
public function applyToStyleContainer(StyleContainer $styles): StyleContainer {
if ($this->scale !== null) {
if ($this->scale->x < 0) {
$styles->fry = 180;
}
$styles->fscx = round(abs($this->scale->x) * 100, 2);
if ($this->scale->y < 0) {
$styles->frx = 180;
}
$styles->fscy = round(abs($this->scale->y) * 100, 2);
} else {
$styles->fry = null;
$styles->fscx = null;
$styles->frx = null;
$styles->fscy = null;
}
if ($this->skew !== null) {
$styles->fax = round($this->skew->x, 4);
$styles->fay = round($this->skew->y, 4);
} else {
$styles->fax = null;
$styles->fay = null;
}
if ($this->translation !== null) {
$styles->pos = ($styles->pos ?? new Vector2(0, 0))->add($this->translation);
} else {
$styles->pos = null;
}
return $styles;
}
public function equals(MatrixTransform $other, $epsilon = Constants::EPSILON): bool {
return $this->matrix->equals($other->matrix, $epsilon);
}
static function fromXML(\DOMElement $element): MatrixTransform {
return new MatrixTransform($element->hasAttribute("scaleX") ? new Vector2(floatval($element->getAttribute("scaleX")), floatval($element->getAttribute("scaleY"))) : null, $element->hasAttribute("skewX") ? new Vector2(floatval($element->getAttribute("skewX")), floatval($element->getAttribute("skewY"))) : null, $element->hasAttribute("transX") ? new Vector2(intval($element->getAttribute("transX")), intval($element->getAttribute("transY"))) : null,);
}
}