---
title: Spinning spatial cross
description: We are writing an algorithm for rotating a three-dimensional figure around its center along all three axes at once. In the previous example, we rotated cube...
sections: [Volumetric figures,Rotation matrix,Experimental model]
tags: [javascript,online,canvas,geometry,matrix,graphics,image,picture,square,cube,3d,three-dimensional]
scripts: [/js/classes-point-cube.js,/js/spinning-spatial-cross.js,/js/spinning-spatial-cross2.js]
styles: [/css/pomodoro1.css]
canonical_url: /en/2023/01/16/spinning-spatial-cross.html
url_translated: /ru/2023/01/15/spinning-spatial-cross.html
title_translated: Вращаем пространственный крест
date: 2023.01.16
lang: en
---
We are writing an algorithm for rotating a three-dimensional figure around
its center along all three axes at once. In the previous example, we
[rotated cube in space]({{ '/en/2023/01/11/spinning-cube-in-space.html' | relative_url }})
— in this example, there are a lot of cubes, the algorithm will be almost the same, and we will use
the same formulas. For clarity, let's take two variants of a symmetrical volumetric figure in two
types of projections — *spatial cross* and *cross-cube* — we consider the difference between them.
Testing the experimental interface: [Volumetric tetris]({{ '/en/2023/01/22/volumetric-tetris.html' | relative_url }}).
{% include heading.html text="Spatial cross" hash="spatial-cross" %}
Parallel projection
Perspective projection
{% include heading.html text="Cross-cube" hash="cross-cube" %}
Parallel projection
Perspective projection
*Parallel projection* — all cubes are the same size.
*Perspective projection* — the cubes look shrinking in the distance.
{% include heading.html text="Experimental model" hash="experimental-model" %}
Slightly complicated version from the previous example — now there are a lot of cubes. In addition to the
previous settings there can be changed: variant of the figure — *spatial cross* or *cross-cube*, face sorting
direction — *straight perspective* or *reverse perspective* and transparency of the cube walls.
Variant of the figure:
Linear perspective:
{% include heading.html text="Algorithm description" hash="algorithm-description" %}
We prepare a three-dimensional matrix of zeros and ones, where one means a cube in a certain place of the figure.
Then we bypass this matrix and fill in the array of cubes with the corresponding coordinates of the vertices.
After that, we start the rotation along all three axes at once. At each step, we bypass the array of cubes and
get projections of their faces. Then we sort the array of faces by remoteness from the projection center, bypass
this array and throw away the same pairs from it — these are the adjacent walls between neighboring cubes inside
the figure. After that we draw with a translucent color the cube faces — first the distant, and then the near ones,
so that the distant faces can be seen through the near ones.
{% include heading.html text="Implementation in JavaScript" hash="implementation-in-javascript" %}
{% include classes-point-cube-en.md -%}
Create objects according to templates and draw their projections on the plane.
```js
'use strict';
// matrices-templates for cubes
const shape1 = [ // spatial cross
[[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 = [ // cross-cube
[[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]]];
// cube size, number of cubes in a row, indent
const size = 40, row = 5, gap = 50;
// arrays for cubes
const cubes1 = [], cubes2 = [];
// bypass the matrices, fill the arrays with cubes
for (let x=0; xMath.abs(b.dist-a.dist)>size ? b.dist-a.dist : b.clock-a.clock);
// sort the faces by remoteness from the projection center
perspective.sort((a,b)=>b.dist-a.dist);
// draw parallel projection
drawFigure(cnv1, parallel);
// draw perspective projection
drawFigure(cnv2, perspective);
}
```
```js
// do not draw adjacent walls between neighboring cubes
function noAdjacent(array) {
// sort the faces by remoteness
array.sort((a,b) => b.dist-a.dist);
// remove the adjacent walls between cubes
for (let i=0, j=1; isetInterval(repaint,50));
```