Перейти к основному содержимому

Работа с геометрией

Всем

Play ITЗагрузка интерактивного демо…


Работа с геометрией​

Теория 2D/3D, GPU и конвейера — в статье Графические данные. Здесь — координаты и преобразования в UI, Canvas, играх и картографии.

Геометрия в программировании представляет собой фундамент для всего, что связано с отображением, перемещением и измерением объектов на экране или в виртуальном пространстве. Любая графика, интерфейс, игра, карта или чертёж опираются на математический аппарат координат, размеров и преобразований. Понимание этих концепций позволяет создавать предсказуемое поведение визуальных элементов и управлять ими через код.


Координаты и системы координат​

Координата — это числовое значение, определяющее положение точки в заданном пространстве относительно выбранной системы отсчёта. Координата отвечает на вопрос "где находится объект" и выражается одним или несколькими числами в зависимости от размерности пространства.

Система координат — это совокупность правил и опорных элементов, позволяющих однозначно задать положение любой точки. В её состав входят начало отсчёта, направления осей и единицы измерения.


Декартова система координат​

Декартова система координат использует перпендикулярные оси, пересекающиеся в начале отсчёта. Каждая ось имеет своё направление и имя. Положение точки описывается набором чисел, соответствующих проекциям точки на эти оси.

ОсьНаправление в классической математикеНазвание координаты
XВправоАбсцисса
YВверхОрдината
ZНа наблюдателяАппликата

Декартова система удобна тем, что любые операции над точками сводятся к простым арифметическим действиям. Сложение, вычитание и умножение координат дают новые положения, расстояния и направления.


Полярная система координат​

Полярная система координат описывает точку на плоскости через расстояние от центра и угол относительно выбранного направления. Она удобна для задач, связанных с вращением, орбитальным движением и круговыми траекториями.

Параметры полярной системы:

  • радиус — расстояние от начала координат до точки;
  • угол — поворот относительно нулевого направления, обычно против часовой стрелки.

Цилиндрическая и сферическая системы​

Цилиндрическая система расширяет полярную на трёхмерное пространство добавлением оси высоты. Она удобна для описания объектов с осевой симметрией — труб, колонн, вращающихся тел.

Сферическая система использует радиус и два угла для описания положения точки в трёхмерном пространстве. Она удобна для задач астрономии, навигации и работы с панорамными изображениями.


Экранная система координат​

Экранная система координат отличается от классической математической направлением оси Y. На экране и в большинстве графических библиотек ось Y направлена вниз, а не вверх. Это наследие старых электронно-лучевых трубок, где развёртка изображения шла сверху вниз.

ХарактеристикаМатематическая системаЭкранная система
Направление оси XВправоВправо
Направление оси YВверхВниз
Начало координатОбычно в центреВ левом верхнем углу
Единица измеренияУсловнаяПиксель

Эта особенность приводит к тому, что увеличение координаты Y перемещает объект ниже на экране, что противоречит школьной интуиции и требует внимания при переносе математических алгоритмов в графику.


Двумерное и трёхмерное пространство​

Двумерное пространство​

Двумерное пространство описывается двумя осями — X и Y. Оно образует плоскость, на которой можно размещать точки, линии, многоугольники и любые фигуры. Все интерфейсы, спрайты, элементы веб-страниц и 2D-игры существуют именно в таком пространстве.

Свойства двумерного пространства:

  • любая точка описывается парой чисел;
  • параллельные прямые сохраняют расстояние между собой;
  • фигуры имеют площадь и периметр;
  • преобразования включают перенос, поворот и масштабирование.

Трёхмерное пространство​

Трёхмерное пространство добавляет ось Z, что позволяет описывать объекты с глубиной. В играх, симуляциях, системах автоматизированного проектирования и виртуальной реальности используются именно трёхмерные координаты.

Особенности трёхмерного пространства:

  • точка описывается тройкой чисел;
  • появляется понятие объёма;
  • добавляются новые оси вращения;
  • возникают задачи видимости и скрытия поверхностей;
  • требуется камера для проекции 3D-сцены на 2D-экран.

Правая и левая ориентация​

Трёхмерные системы координат бывают право-ориентированными и лево-ориентированными. Различие заключается в направлении оси Z относительно осей X и Y. OpenGL использует правую систему, DirectX и Unity — левую. Это важно учитывать при переносе алгоритмов и моделей между движками.


Размеры экрана и плоскость​

Пиксель и разрешение​

Пиксель — это минимальная единица отображения на экране, имеющая собственный цвет и положение. Совокупность пикселей образует изображение.

Разрешение экрана — это количество пикселей по горизонтали и вертикали. Типичные значения включают 1920×1080, 2560×1440, 3840×2160. Чем выше разрешение, тем более детализированное изображение способен отобразить экран.


Viewport и рабочая область​

Viewport — это видимая часть виртуального пространства, отображаемая в данный момент на экране. В браузере viewport соответствует размеру окна просмотра, в игре — области, захватываемой камерой, в графическом редакторе — видимой части холста.

Плоскость в компьютерной графике представляет собой бесконечное или ограниченное двумерное пространство, в котором размещаются объекты. Координаты на плоскости могут выходить за пределы viewport, и тогда такие объекты оказываются за границей видимой области.


Логические и физические координаты​

Современные экраны имеют разную плотность пикселей. На дисплеях с высокой плотностью один логический пиксель может занимать несколько физических. Это соотношение называется devicePixelRatio в JavaScript и учитывается при точной отрисовке.

Тип координатОписаниеИспользование
ФизическиеРеальные пиксели матрицыНизкоуровневая отрисовка
ЛогическиеМасштабированные единицыИнтерфейс, CSS, вёрстка
МировыеКоординаты в виртуальном пространствеИгры, редакторы, карты
ЛокальныеКоординаты относительно объектаАнимация, вложенные элементы

Позиционирование​

Позиционирование — это процесс задания положения объекта в пространстве относительно выбранной системы отсчёта. Положение может задаваться абсолютно, относительно родителя, относительно окна или относительно другого объекта.


Абсолютное позиционирование​

Абсолютное позиционирование привязывает объект к фиксированным координатам в общей системе. Такой объект сохраняет своё положение независимо от перемещений других элементов.


Относительное позиционирование​

Относительное позиционирование задаёт смещение объекта от его нормального положения или от положения родительского элемента. Это удобно для вложенных структур, где дочерние элементы следуют за родителем.


Якоря и опорные точки​

Якорь — это точка объекта, которая совмещается с заданными координатами. По умолчанию якорем часто выступает левый верхний угол, но для вращения и масштабирования удобнее использовать центр объекта.

Опорные точки для разных операций:

  • перемещение — любая точка, обычно центр;
  • вращение — центр масс или заданный pivot;
  • масштабирование — центр или угол;
  • выравнивание — граница или центр.

Пример позиционирования на Python с использованием turtle​


import turtle

screen = turtle.Screen()
screen.setup(width=800, height=600)
screen.title("Позиционирование")

pen = turtle.Turtle()
pen.shape("turtle")
pen.speed(3)

pen.penup()
pen.goto(0, 0)
pen.stamp()

pen.goto(200, 150)
pen.stamp()

pen.goto(-200, -100)
pen.stamp()

screen.mainloop()

Разбор примера:

  • turtle.Screen() создаёт окно отрисовки с собственной системой координат;
  • screen.setup(width=800, height=600) задаёт размеры окна в пикселях;
  • pen.penup() поднимает перо, чтобы черепаха перемещалась без рисования линии;
  • pen.goto(x, y) устанавливает абсолютные координаты черепахи;
  • pen.stamp() оставляет отпечаток формы в текущей позиции;
  • начало координат в turtle располагается в центре окна, ось Y направлена вверх.

Прокрутка​

Прокрутка — это механизм перемещения видимой области относительно более крупного содержимого. Когда контент превышает размеры viewport, пользователь сдвигает область просмотра, чтобы увидеть скрытые части.


Принципы работы прокрутки​

Прокрутка реализуется через смещение начальной точки viewport. Содержимое остаётся на месте, а камера сдвигается вдоль одной или двух осей. Координаты видимой области изменяются, что создаёт эффект движения контента.

Параметры прокрутки:

  • текущее смещение по X;
  • текущее смещение по Y;
  • общие размеры содержимого;
  • размеры viewport;
  • максимальные значения смещения.

Виртуальная прокрутка​

При работе с огромными списками или таблицами применяется виртуализация. В памяти хранятся только те элементы, которые находятся в пределах viewport и небольшого буфера. При прокрутке невидимые элементы удаляются, а новые создаются на лету.


Пример обработки прокрутки на JavaScript​

const container = document.querySelector('.scroll-container');

container.addEventListener('scroll', function(event) {
const scrollLeft = event.target.scrollLeft;
const scrollTop = event.target.scrollTop;
const scrollWidth = event.target.scrollWidth;
const scrollHeight = event.target.scrollHeight;
const clientWidth = event.target.clientWidth;
const clientHeight = event.target.clientHeight;

console.log('Горизонтальное смещение:', scrollLeft);
console.log('Вертикальное смещение:', scrollTop);
console.log('Общая ширина контента:', scrollWidth);
console.log('Общая высота контента:', scrollHeight);
console.log('Видимая ширина:', clientWidth);
console.log('Видимая высота:', clientHeight);
});

Разбор примера:

  • container.addEventListener('scroll', ...) подписывается на событие прокрутки контейнера;
  • scrollLeft и scrollTop содержат текущее смещение видимой области;
  • scrollWidth и scrollHeight отражают полные размеры прокручиваемого содержимого;
  • clientWidth и clientHeight показывают размеры самой видимой области;
  • разность между scrollWidth и clientWidth даёт максимальное горизонтальное смещение.

Масштаб и масштабирование​

Масштаб — это коэффициент, определяющий соотношение между размерами объекта в виртуальном пространстве и на экране. Масштабирование изменяет этот коэффициент, увеличивая или уменьшая видимые размеры.


Коэффициент масштаба​

Коэффициент масштаба выражается числом. Значение единица соответствует обычному размеру, значения больше единицы увеличивают объект, значения меньше единицы уменьшают его.

КоэффициентЭффект
0.5Уменьшение в два раза
1.0Исходный размер
2.0Увеличение в два раза
10.0Десятикратное увеличение

Равномерное и неравномерное масштабирование​

Равномерное масштабирование изменяет размеры объекта пропорционально по всем осям. Пропорции фигуры сохраняются, круг остаётся кругом, квадрат — квадратом.

Неравномерное масштабирование применяет разные коэффициенты к разным осям. Это приводит к искажению формы: круг превращается в эллипс, квадрат — в прямоугольник.


Точка масштабирования​

Масштабирование всегда выполняется относительно некоторой точки. При увеличении карты в браузере такой точкой выступает положение курсора. При увеличении фотографии — центр viewport. Выбор точки определяет, какая часть объекта останется неподвижной во время трансформации.


Пример масштабирования на Canvas в JavaScript​

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 600;

let scale = 1.0;
let offsetX = 0;
let offsetY = 0;

function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(offsetX, offsetY);
ctx.scale(scale, scale);

ctx.fillStyle = '#3498db';
ctx.fillRect(100, 100, 200, 150);

ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.arc(400, 300, 50, 0, Math.PI * 2);
ctx.fill();

ctx.restore();
}

canvas.addEventListener('wheel', function(event) {
event.preventDefault();
const delta = event.deltaY > 0 ? 0.9 : 1.1;
scale = scale * delta;
draw();
});

draw();

Разбор примера:

  • canvas.getContext('2d') получает контекст для двумерной отрисовки;
  • ctx.save() сохраняет текущее состояние трансформаций;
  • ctx.translate(offsetX, offsetY) сдвигает начало координат;
  • ctx.scale(scale, scale) применяет равномерное масштабирование;
  • ctx.restore() возвращает состояние до преобразований;
  • событие wheel отслеживает прокрутку колесом мыши и изменяет коэффициент;
  • event.preventDefault() останавливает стандартную прокрутку страницы.

Панорамирование​

Панорамирование — это перемещение камеры или viewport по сцене без изменения масштаба. Пользователь как бы двигает лист бумаги под увеличительным стеклом, рассматривая разные части изображения.


Отличие от прокрутки​

Панорамирование и прокрутка близки по смыслу, но применяются в разных контекстах. Прокрутка относится к документам и интерфейсам с фиксированной структурой. Панорамирование относится к свободным сценам — картам, редакторам, играм — где содержимое может простираться в любом направлении.


Реализация через перетаскивание​

Классический способ панорамирования — захват сцены мышью и перемещение. При нажатии кнопки фиксируется начальная точка, при движении вычисляется смещение, которое прибавляется к текущим координатам камеры.


Пример панорамирования в pygame​


import pygame
import sys

pygame.init()

screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Панорамирование")

camera_x = 0
camera_y = 0
dragging = False
last_mouse_x = 0
last_mouse_y = 0

objects = [
{"x": 100, "y": 100, "w": 120, "h": 80, "color": (52, 152, 219)},
{"x": 400, "y": 300, "w": 150, "h": 100, "color": (231, 76, 60)},
{"x": -200, "y": -150, "w": 180, "h": 120, "color": (46, 204, 113)},
{"x": 700, "y": -300, "w": 100, "h": 160, "color": (241, 196, 15)},
]

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
dragging = True
last_mouse_x, last_mouse_y = event.pos
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
current_x, current_y = event.pos
delta_x = current_x - last_mouse_x
delta_y = current_y - last_mouse_y
camera_x += delta_x
camera_y += delta_y
last_mouse_x = current_x
last_mouse_y = current_y

# Если сцена "едет" не за мышью — поменяйте знак у delta_x / delta_y

screen.fill((30, 30, 30))

for obj in objects:
screen_x = obj["x"] + camera_x
screen_y = obj["y"] + camera_y
rect = pygame.Rect(screen_x, screen_y, obj["w"], obj["h"])
pygame.draw.rect(screen, obj["color"], rect)

pygame.display.flip()

pygame.quit()
sys.exit()

Разбор примера:

  • pygame.init() инициализирует библиотеку;
  • pygame.display.set_mode() создаёт окно заданных размеров;
  • переменные camera_x и camera_y хранят смещение камеры;
  • MOUSEBUTTONDOWN с button == 1 означает нажатие левой кнопки мыши;
  • при движении мыши с зажатой кнопкой вычисляется дельта смещения;
  • к мировым координатам каждого объекта прибавляется смещение камеры;
  • pygame.draw.rect() рисует прямоугольник в экранных координатах;
  • pygame.display.flip() обновляет содержимое окна.

Полные игровые циклы, столкновения и мини-проекты на Pygame — в Pygame — мини-игры на Python; теория — Разработка игр на Python. Для 3D в движке — Unity C# — скрипты и Разработка на Unity.


Сочетание преобразований​

В реальных приложениях масштабирование, панорамирование и позиционирование применяются вместе. Порядок применения трансформаций имеет значение. Масштабирование с последующим переносом даёт иной результат, чем перенос с последующим масштабированием.


Матричный подход​

Поворот на 90° вокруг начала (математическая система, Y вверх) — (x, y) → (-y, x). В экранной системе (Y вниз) знаки у поворота и отражений меняются — см. таблицу выше.

В CSS те же идеи: transform: translate(10px, 20px) scale(1.5); в Canvas — translate и scale перед рисованием.

Любое аффинное преобразование в 2D описывается матрицей 3×3. Последовательные преобразования перемножаются в одну матрицу — порядок операций важен — сначала масштаб, потом сдвиг даёт другой результат, чем наоборот.


Иерархия координат​

Объекты часто имеют собственную локальную систему координат, вложенную в родительскую. Мировые координаты получаются последовательным применением всех родительских трансформаций. Такой подход используется в игровых движках, SVG, CSS и графических редакторах.

Уровни иерархии координат:

  • локальные координаты объекта;
  • координаты родительского контейнера;
  • координаты сцены;
  • координаты камеры;
  • экранные координаты.

Примеры работы с геометрией в JavaScript и Python​

Рисование сетки координат на Canvas​

function drawGrid(ctx, step, width, height) {
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 1;

for (let x = 0; x <= width; x += step) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}

for (let y = 0; y <= height; y += step) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}

ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;

ctx.beginPath();
ctx.moveTo(width / 2, 0);
ctx.lineTo(width / 2, height);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(0, height / 2);
ctx.lineTo(width, height / 2);
ctx.stroke();
}

const canvas = document.getElementById('gridCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;

drawGrid(ctx, 50, canvas.width, canvas.height);

Разбор примера:

  • функция drawGrid принимает контекст, шаг сетки и размеры холста;
  • первый цикл рисует вертикальные линии через каждые step пикселей;
  • второй цикл рисует горизонтальные линии;
  • жирные линии отмечают центр холста, имитируя оси координат;
  • ctx.beginPath() начинает новый путь, ctx.moveTo() и ctx.lineTo() задают точки.

Геометрические фигуры в turtle​


import turtle
import math

screen = turtle.Screen()
screen.setup(width=800, height=600)

pen = turtle.Turtle()
pen.speed(5)

def draw_square(t, x, y, size):
t.penup()
t.goto(x, y)
t.pendown()
for _ in range(4):
t.forward(size)
t.left(90)

def draw_circle(t, x, y, radius):
t.penup()
t.goto(x, y - radius)
t.pendown()
t.circle(radius)

def draw_triangle(t, x, y, size):
t.penup()
t.goto(x, y)
t.pendown()
for _ in range(3):
t.forward(size)
t.left(120)

draw_square(pen, -200, 100, 100)
draw_circle(pen, 50, 100, 60)
draw_triangle(pen, 200, 50, 120)

screen.mainloop()

Разбор примера:

  • draw_square перемещает черепаху в указанную точку и рисует квадрат через цикл из четырёх сторон;
  • draw_circle учитывает, что turtle.circle() рисует окружность над текущей позицией, поэтому происходит корректировка по Y;
  • draw_triangle использует поворот на 120 градусов для построения равностороннего треугольника;
  • каждая функция принимает координаты x и y, демонстрируя параметрическое позиционирование.

Геометрия в пользовательских интерфейсах​

Элементы интерфейса располагаются в прямоугольных областях, описываемых четырьмя числами — координатами левого верхнего угла и размерами. В CSS эти параметры выражаются свойствами left, top, width, height. В графических редакторах и играх — структурами Rect или BoundingBox.


Ограничивающие прямоугольники​

Ограничивающий прямоугольник — это минимальный прямоугольник со сторонами, параллельными осям, который полностью содержит объект. Он используется для быстрых проверок столкновений, отсечения невидимых частей и определения попадания курсора.


Вычисление расстояний и пересечений​

Две распространённые задачи в интерфейсах и играх — проверка расстояния между объектами и проверка пересечения прямоугольников. Обе решаются простыми сравнениями координат и размеров.


Пример проверки пересечения на JavaScript​

function rectanglesIntersect(rectA, rectB) {
const aLeft = rectA.x;
const aRight = rectA.x + rectA.width;
const aTop = rectA.y;
const aBottom = rectA.y + rectA.height;

const bLeft = rectB.x;
const bRight = rectB.x + rectB.width;
const bTop = rectB.y;
const bBottom = rectB.y + rectB.height;

const overlapX = aLeft < bRight && aRight > bLeft;
const overlapY = aTop < bBottom && aBottom > bTop;

return overlapX && overlapY;
}

const player = { x: 100, y: 100, width: 50, height: 50 };
const obstacle = { x: 130, y: 120, width: 60, height: 60 };

if (rectanglesIntersect(player, obstacle)) {
console.log('Обнаружено столкновение');
}

Разбор примера:

  • для каждого прямоугольника вычисляются координаты всех четырёх сторон;
  • overlapX становится истиной, когда горизонтальные проекции прямоугольников пересекаются;
  • overlapY проверяет пересечение вертикальных проекций;
  • итоговое пересечение имеет место при одновременном выполнении обоих условий;
  • этот подход называется Axis-Aligned Bounding Box и применяется повсеместно в 2D-играх.

Камера и виды проекций​

В трёхмерных сценах камера определяет, какая часть мира попадает на экран. Положение камеры, направление взгляда и параметры объектива формируют итоговую картинку.


Параметры камеры​

Камера описывается несколькими ключевыми параметрами:

  • положение в мировых координатах;
  • направление взгляда;
  • вектор "вверх", определяющий ориентацию;
  • угол обзора;
  • ближняя и дальняя плоскости отсечения.

Ортографическая и перспективная проекция​

Ортографическая проекция сохраняет параллельность линий и используется в чертежах, стратегических играх и изометрических видах. Размеры объектов остаются постоянными независимо от расстояния до камеры.

Перспективная проекция имитирует человеческое зрение: удалённые объекты выглядят меньше, параллельные линии сходятся в точке схода. Она применяется в 3D-играх, симуляторах и архитектурной визуализации.


Применения в реальных задачах​

Геометрические вычисления встречаются во множестве областей программирования. Карты и навигация используют координаты широты и долготы с последующим проецированием на плоскость. Графические редакторы оперируют трансформациями слоёв. Веб-разработчики управляют позиционированием блоков и адаптивной вёрсткой. Разработчики игр рассчитывают траектории, столкновения и физику.

Области применения геометрических вычислений:

  • геоинформационные системы и карты;
  • компьютерные игры и симуляции;
  • графические редакторы и CAD-системы;
  • обработка изображений и компьютерное зрение;
  • робототехника и управление дронами;
  • виртуальная и дополненная реальность;
  • визуализация данных и инфографика;
  • пользовательские интерфейсы и вёрстка.

Понимание координат, систем отсчёта и преобразований создаёт прочную основу для работы в любой из этих областей. Дальнейшее изучение включает матричные операции, кватернионы для вращения в трёхмерном пространстве, кривые Безье для плавных траекторий и пространственные структуры данных для эффективного поиска объектов. Углублённый маршрут для программистов CG — раздел Компьютерная графика (2D-отсечение, OpenGL).


Содержание