--- title: Вращаем пространственный крест description: Пишем алгоритм для поворота объёмной фигуры на угол вокруг своего центра по всем трём осям сразу. В предыдущем примере мы вращали куб в пространстве... sections: [Объёмные фигуры,Матрица поворота,Экспериментальная модель] tags: [javascript,онлайн,canvas,геометрия,матрица,графика,изображение,картинка,квадрат,куб] 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" %}
Параллельная проекция

Ваш браузер не поддерживает Canvas

Перспективная проекция

Ваш браузер не поддерживает Canvas

{% include heading.html text="Крест-куб" hash="cross-cube" %}
Параллельная проекция

Ваш браузер не поддерживает Canvas

Перспективная проекция

Ваш браузер не поддерживает Canvas

*Параллельная проекция* — все кубики одинакового размера. *Перспективная проекция* — кубики выглядят уменьшающимися вдалеке. {% include heading.html text="Экспериментальная модель" hash="experimental-model" %} Слегка усложнённая версия из предыдущего примера — теперь кубиков много. В дополнение к предыдущим настройкам можно поменять: вариант фигуры — *пространственный крест* или *крест-куб*, направление сортировки граней — *линейная перспектива* или *обратная перспектива* и прозрачность стенок кубиков.

Ваш браузер не поддерживает Canvas

Вращение по осям:
Центр на экране наблюдателя:
150
150
125
Удалённость центра проекции:
300
Прозрачность кубиков:
20%
Вариант фигуры:
Перспективная проекция:
{% 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)); ```