Отражение геообъектов в двумерной системе координат в контексте GeoJSON представляет собой аффинное преобразование, сохраняющее расстояния до оси симметрии с изменением ориентации. В библиотеке Turf.js такие операции реализуются через комбинации базовых трансформаций: масштабирование, поворот и перенос, поскольку отдельной специализированной функции «mirror» в ядре библиотеки нет.
Ключевое свойство отражения — инверсия одной из координат относительно выбранной оси или линии симметрии при сохранении топологической структуры объекта.
Все операции выполняются над объектами GeoJSON:
PointLineStringPolygonFeatureFeatureCollectionКаждый объект рассматривается как набор координат в плоской декартовой системе. Turf.js предоставляет набор утилит для трансформации:
@turf/helpers@turf/transform-translate@turf/transform-rotate@turf/transform-scale@turf/bbox@turf/centerГеометрия трактуется как неизменяемая структура, поэтому каждая операция возвращает новый объект.
Самый простой случай — отражение относительно оси X или Y. В терминах координат:
(x, y) → (x, -y)(x, y) → (-x, y)В Turf.js прямого вызова нет, но отражение относительно начала координат реализуется через масштабирование.
Функция transformScale позволяет выполнять инверсию
координат через отрицательные коэффициенты:
import { transformScale } from "@turf/transform-scale";
const mirrored = transformScale(feature, -1, -1);
Такое преобразование выполняет центральную симметрию относительно центра масштабирования. Важный аспект — центр операции.
По умолчанию используется центр bounding box, что определяется через:
bbox(feature)Это приводит к отражению относительно геометрического центра, а не начала координат.
Для контроля точки симметрии применяется предварительное смещение:
import { transformTranslate } from "@turf/transform-translate";
import { transformScale } from "@turf/transform-scale";
import { center } from "@turf/center";
const c = center(feature);
const moved = transformTranslate(feature, -c.geometry.coordinates[0], -c.geometry.coordinates[1]);
const scaled = transformScale(moved, -1, -1);
const restored = transformTranslate(scaled, c.geometry.coordinates[0], c.geometry.coordinates[1]);
Такой подход позволяет зафиксировать центр отражения в произвольной точке.
Центральная симметрия не всегда эквивалентна осевому отражению. Для имитации отражения относительно оси X или Y применяется раздельное масштабирование координат.
Инверсия X-координаты:
const mirrorY = transformScale(feature, -1, 1);
Инверсия Y-координаты:
const mirrorX = transformScale(feature, 1, -1);
Эти операции корректны только при условии, что ось проходит через центр трансформации.
Использование transformScale имеет ряд особенностей:
Для точного контроля требуется комбинирование трансформаций.
Наиболее общий случай — отражение относительно линии вида
Ax + By + C = 0. Turf.js не предоставляет прямой функции,
поэтому применяется композиция преобразований:
Пусть задана линия отражения. Тогда последовательность операций:
const translated = transformTranslate(feature, -cx, -cy);
где (cx, cy) — точка на линии отражения.
const rotated = transformRotate(translated, -angle);
Угол определяется направлением линии:
const angle = Math.atan2(y2 - y1, x2 - x1);
const mirrored = transformScale(rotated, 1, -1);
const unrotated = transformRotate(mirrored, angle);
const finalResult = transformTranslate(unrotated, cx, cy);
import { transformTranslate } from "@turf/transform-translate";
import { transformRotate } from "@turf/transform-rotate";
import { transformScale } from "@turf/transform-scale";
function reflectAcrossLine(feature, x1, y1, x2, y2) {
const cx = x1;
const cy = y1;
const angle = Math.atan2(y2 - y1, x2 - x1);
const translated = transformTranslate(feature, -cx, -cy);
const rotated = transformRotate(translated, -angle);
const mirrored = transformScale(rotated, 1, -1);
const unrotated = transformRotate(mirrored, angle);
const restored = transformTranslate(unrotated, cx, cy);
return restored;
}
При работе с Polygon и MultiPolygon важно
учитывать:
Для FeatureCollection применяется итерация:
collection.features.map(f => reflectAcrossLine(f, x1, y1, x2, y2));
В некоторых сценариях отражение выполняется относительно границ объекта:
import bbox from "@turf/bbox";
const [minX, minY, maxX, maxY] = bbox(feature);
Центр вычисляется как:
(minX + maxX) / 2(minY + maxY) / 2Это позволяет стабилизировать отражение в пределах геометрического контура.
При многократных трансформациях возникают эффекты:
Для минимизации ошибок применяется:
Стоимость операции линейно зависит от числа вершин:
O(n) для LineStringO(n log n) в сложных композициях FeatureCollectionОптимизация достигается:
Отражение часто используется вместе с:
transformTranslate для позиционированияtransformRotate для выравнивания объектовtransformScale для изменения масштаба сценыКомпозиция формирует полноценную аффинную матрицу преобразований, эквивалентную:
M = T × R × S × R⁻¹ × T⁻¹
где каждая операция соответствует шагу отражения относительно произвольной оси.