---
title: Вращаем пространственный крест
description: Пишем алгоритм для поворота трёхмерной фигуры вокруг своего центра по всем трём осям сразу. В предыдущем примере мы вращали куб в пространстве — в этом...
sections: [Объёмные фигуры,Матрица поворота,Экспериментальная модель]
tags: [javascript,онлайн,canvas,геометрия,матрица,графика,изображение,картинка,квадрат,куб,3д,трёхмерный]
scripts: [/js/classes-point-cube.js,/js/spinning-spatial-cross.js,/js/spinning-spatial-cross2.js]
styles: [/css/pomodoro1.css]
canonical_url: /ru/2023/01/15/spinning-spatial-cross.html
url_translated: /en/2023/01/16/spinning-spatial-cross.html
title_translated: Spinning spatial cross
date: 2023.01.15
---
Пишем алгоритм для поворота трёхмерной фигуры вокруг своего центра по всем трём осям сразу. В предыдущем
примере мы [вращали куб в пространстве]({{ '/ru/2023/01/10/spinning-cube-in-space.html' | relative_url }})
— в этом примере кубиков будет много, алгоритм будет почти такой же, и формулы будем использовать те же. Для
наглядности возьмём два варианта симметричной объёмной фигуры в двух типах проекций — *пространственный крест*
и *крест-куб* — рассматриваем разницу между ними.
Тестирование экспериментального интерфейса: [Объёмный тетрис]({{ '/ru/2023/01/21/volumetric-tetris.html' | relative_url }}).
{% include heading.html text="Пространственный крест" hash="spatial-cross" %}
Параллельная проекция
Перспективная проекция
{% include heading.html text="Крест-куб" hash="cross-cube" %}
Параллельная проекция
Перспективная проекция
*Параллельная проекция* — все кубики одинакового размера.
*Перспективная проекция* — кубики выглядят уменьшающимися вдалеке.
{% include heading.html text="Экспериментальная модель" hash="experimental-model" %}
Слегка усложнённая версия из предыдущего примера — теперь кубиков много. В дополнение к предыдущим настройкам
можно поменять: вариант фигуры — *пространственный крест* или *крест-куб*, направление сортировки граней
— *линейная перспектива* или *обратная перспектива* и прозрачность стенок кубиков.
Вариант фигуры:
Перспективная проекция:
{% include heading.html text="Описание алгоритма" hash="algorithm-description" %}
Подготавливаем трёхмерную матрицу из нулей и единиц, где единица означает кубик в определенном месте фигуры.
Затем обходим эту матрицу и заполняем массив кубиков с соответствующими координатами вершин. После этого
запускаем вращение по всем трём осям сразу. На каждом шаге обходим массив кубиков и получаем проекции их
граней. Затем сортируем массив граней по удалённости от центра проекции, обходим этот массив и выкидываем
из него одинаковые пары — это есть смежные стенки между соседними кубиками внутри фигуры. После этого
рисуем полупрозрачным цветом грани кубиков — сначала дальние, а затем ближние, чтобы через ближние грани
было видно дальние.
{% include heading.html text="Реализация на JavaScript" hash="implementation-in-javascript" %}
{% include classes-point-cube-ru.md -%}
Создаём объекты по шаблонам и рисуем их проекции на плоскости.
```js
'use strict';
// матрицы-шаблоны для кубиков
const shape1 = [ // пространственный крест
[[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
[[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
[[0,0,1,0,0], [0,0,1,0,0], [1,1,1,1,1], [0,0,1,0,0], [0,0,1,0,0]],
[[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
[[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]]];
const shape2 = [ // крест-куб
[[0,0,1,0,0], [0,0,1,0,0], [1,1,1,1,1], [0,0,1,0,0], [0,0,1,0,0]],
[[0,0,1,0,0], [0,0,0,0,0], [1,0,0,0,1], [0,0,0,0,0], [0,0,1,0,0]],
[[1,1,1,1,1], [1,0,0,0,1], [1,0,0,0,1], [1,0,0,0,1], [1,1,1,1,1]],
[[0,0,1,0,0], [0,0,0,0,0], [1,0,0,0,1], [0,0,0,0,0], [0,0,1,0,0]],
[[0,0,1,0,0], [0,0,1,0,0], [1,1,1,1,1], [0,0,1,0,0], [0,0,1,0,0]]];
// размер кубика, количество кубиков в ряду, отступ
const size = 40, row = 5, gap = 50;
// массивы для кубиков
const cubes1 = [], cubes2 = [];
// обходим матрицы, заполняем массивы кубиками
for (let x=0; xMath.abs(b.dist-a.dist)>size ? b.dist-a.dist : b.clock-a.clock);
// сортируем грани по удалённости от центра проекции
perspective.sort((a,b)=>b.dist-a.dist);
// рисуем параллельную проекцию
drawFigure(cnv1, parallel);
// рисуем перспективную проекцию
drawFigure(cnv2, perspective);
}
```
```js
// смежные стенки между соседними кубиками не рисуем
function noAdjacent(array) {
// сортируем грани по удалённости
array.sort((a,b) => b.dist-a.dist);
// удаляем смежные стенки между кубиками
for (let i=0, j=1; isetInterval(repaint,50));
```