Скачиваний:
0
Добавлен:
27.12.2025
Размер:
216.59 Кб
Скачать

Реализация матричных преобразований

src/core/math/Matrix.ts

import type { Point } from "../types";

/**

* Класс для работы с матрицами преобразований 3x3.

* Используется для аффинных преобразований в 2D (сдвиг, поворот).

* Хранит данные в плоском массиве: [m00, m01, m02, m10, m11, m12, m20, m21, m22]

*/

export class Matrix {

values: number[];

constructor(values?: number[]) {

if (values) {

if (values.length !== 9) {

throw new Error("Matrix must have exactly 9 values!");

}

this.values = values;

} else {

this.values = [1, 0, 0, 0, 1, 0, 0, 0, 1];

}

}

/**

* Умножение матриц: A * B

* Результат - новая матрица, объединяющая эффекты (сначала B, потом A)

*/

multiply(other: Matrix): Matrix {

const a = this.values;

const b = other.values;

const result: number[] = [];

// Строка 0

result[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];

result[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];

result[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];

// Строка 1

result[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];

result[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];

result[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];

// Строка 2

result[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];

result[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];

result[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];

return new Matrix(result);

}

transformPoint(p: Point): Point {

const m = this.values;

const x = m[0] * p.x + m[1] * p.y + m[2];

const y = m[3] * p.x + m[4] * p.y + m[5];

return { x, y };

}

/**

* Матрица переноса (Translation)

*/

static translation(dx: number, dy: number): Matrix {

return new Matrix([1, 0, dx, 0, 1, dy, 0, 0, 1]);

}

/**

* Матрица поворота (Rotation) вокруг начала координат (0,0)

* @param angleDegrees угол в градусах

*/

static rotation(angleDegrees: number): Matrix {

const rad = (angleDegrees * Math.PI) / 180;

const c = Math.cos(rad);

const s = Math.sin(rad);

return new Matrix([c, -s, 0, s, c, 0, 0, 0, 1]);

}

/**

* Единичная матрица

*/

static identity(): Matrix {

return new Matrix();

}

}

Парсинг и сохранение данных

src/core/parsers/FileParser.ts

import { Polygon, Line, type Point, type SceneData } from "../types";

import { COLORS } from "../theme";

export class FileParser {

/**

* Превращает данные текстового формата в данные сцены

*/

static parse(text: string): SceneData {

const polygons: Polygon[] = [];

let cuttingLine: Line | null = null;

const lines = text

.split("\n")

.map((l) => l.trim())

.filter((l) => l.length > 0);

let currentPolygonPoints: Point[] = [];

let isReadingPolygon = false;

let isReadingLine = false;

let linePoints: Point[] = [];

for (const line of lines) {

if (line === "POLYGON") {

isReadingPolygon = true;

currentPolygonPoints = [];

continue;

}

if (line === "END" && isReadingPolygon) {

if (currentPolygonPoints.length >= 3) {

polygons.push(new Polygon(currentPolygonPoints, COLORS.POLYGON.DEFAULT));

}

isReadingPolygon = false;

continue;

}

if (line === "LINE") {

isReadingLine = true;

linePoints = [];

continue;

}

const parts = line.split(/\s+/);

if (parts.length >= 2) {

const x = parseFloat(parts[0]);

const y = parseFloat(parts[1]);

if (!isNaN(x) && !isNaN(y)) {

const point: Point = { x, y };

if (isReadingPolygon) {

currentPolygonPoints.push(point);

} else if (isReadingLine) {

linePoints.push(point);

}

}

}

}

if (linePoints.length >= 2) {

cuttingLine = new Line(linePoints[0], linePoints[1]);

}

return { polygons, cuttingLine };

}

/**

* Превращает данные сцены обратно в текстовый формат

*/

static save(data: SceneData): string {

const lines: string[] = [];

data.polygons.forEach((poly) => {

lines.push("POLYGON");

poly.vertices.forEach((v) => {

lines.push(`${v.x.toFixed(2)} ${v.y.toFixed(2)}`);

});

lines.push("END");

lines.push("");

});

if (data.cuttingLine) {

lines.push("LINE");

const start = data.cuttingLine.start;

const end = data.cuttingLine.end;

lines.push(`${start.x.toFixed(2)} ${start.y.toFixed(2)}`);

lines.push(`${end.x.toFixed(2)} ${end.y.toFixed(2)}`);

}

return lines.join("\n");

}

}