I have asked this question on ru.stackoverflow.com and have no valid answers.
Specification:
- Coordinate system
- Cube spins around its center on all three axes.
- Turn angle is not known previously.
- Parallel projection calculated by:
x`` = x;
y`` = y + z / 4; 5. Per unit of time only 3 sides, closest to the projection plane, are visible.
Question:
How to determine which are the closest sides?
I'm going this way: take pairs of sides left and right, front and back, top and bottom, then determine closest and farthest points in (Z) axis, determine the equation of a line, take the second farthest point in (Z) axis, and substitute into this equation - so determine the inclination of the side. Based on this choose which side is closer. I want to draw only the visible faces.
This code don't work:
// Получаем параллельную проекцию кубика на плоскость экрана
function getParallelProjection(arr) {
var i, j, k;
var arr_new = [];
// Попарно работаем с гранями
// Левая и правая
arr_new[0] = getSideParallelProjection(arr[0], arr[1], arr[6]);
// Задняя и передняя
arr_new[1] = getSideParallelProjection(arr[2], arr[3], arr[6]);
// Верхняя и нижняя
arr_new[2] = getSideParallelProjection(arr[4], arr[5], arr[6]);
return arr_new;
}
// Параллельная проекция грани
function getSideParallelProjection(side1, side2, cubeCenter) {
// Сначала выясним какая пара нам попалась
var centralProjection1 = getPointParallelProjection(side1[4]);
var centralProjection2 = getPointParallelProjection(side2[4]);
var coordinate = {
x:Math.abs(side1[4].x - side2[4].x),
y:Math.abs(side1[4].y - side2[4].y),
z:Math.abs(side1[4].z - side2[4].z)};
var i;
// Найдем дальнюю (1) и ближнюю (2) от экрана точки
// по оси (Z) и посчитаем их проекции
var point1 = {z:10000},
point2 = {z:-10000},
point3 = {z:10000};
for (i = 0; i < 4; i++) {
if (point1.z > side1[i].z) {
point1 = side1[i];
}
if (point1.z == side1[i].z
&& point1.x > side1[i].x) {
point1 = side1[i];
}
if (point1.z == side1[i].z
&& point1.x == side1[i].x
&& point1.y < side1[i].y) {
point1 = side1[i];
}
if (point2.z < side1[i].z) {
point2 = side1[i];
}
if (point2.z == side1[i].z
&& point2.x < side1[i].x) {
point2 = side1[i];
}
if (point2.z == side1[i].z
&& point2.x == side1[i].x
&& point2.y > side1[i].y) {
point2 = side1[i];
}
}
for (i = 0; i < 4; i++) {
if (point3.z > side1[i].z
&& point1 != side1[i]) {
point3 = side1[i];
}
if (point3.z == side1[i].z
&& point3.x > side1[i].x
&& point1 != side1[i]) {
point3 = side1[i];
}
if (point3.z == side1[i].z
&& point3.x == side1[i].x
&& point3.y < side1[i].y
&& point1 != side1[i]) {
point3 = side1[i];
}
}
var direction = (point3.x - point1.x) / (point2.x - point1.x)
- (point3.y - point1.y) / (point2.y - point1.y);
var projection = [];
// (X) Правая и левая грани
if (coordinate.x > coordinate.y && coordinate.x > coordinate.z) {
point1 = getPointParallelProjection(point1);
point2 = getPointParallelProjection(point2);
point3 = getPointParallelProjection(point3);
var direction = (point3.x - point1.x) / (point2.x - point1.x)
- (point3.y - point1.y) / (point2.y - point1.y);
var selected;
if (point1.x >= point2.x) {
if (centralProjection1.x >= centralProjection2.x) {
selected = side1;
} else {
selected = side2;
}
} else {
if (centralProjection1.x <= centralProjection2.x) {
selected = side1;
} else {
selected = side2;
}
}
if (selected.length < 6) {
for (i = 0; i < 4; i++) {
projection[i] = getPointParallelProjection(selected[i]);
}
projection[4] = 'rgb(200,200,0)';
}
}
// (Z) Передняя и задняя грани
else if (coordinate.z > coordinate.x && coordinate.z > coordinate.y) {
var selected;
if (point1.x >= point2.x && direction < 0) {
if (centralProjection1.x >= centralProjection2.x) {
selected = side1;
} else {
selected = side2;
}
} else {
if (centralProjection1.x <= centralProjection2.x) {
selected = side1;
} else {
selected = side2;
}
}
if (selected.length < 6) {
for (i = 0; i < 4; i++) {
projection[i] = getPointParallelProjection(selected[i]);
}
projection[4] = 'rgb(200,0,0)';
}
}
// (Y) Верхняя и нижняя грани
else {
var selected;
if (point1.y <= point2.y) {
if (centralProjection1.y <= centralProjection2.y) {
selected = side1;
} else {
selected = side2;
}
} else {
if (centralProjection1.y >= centralProjection2.y) {
selected = side1;
} else {
selected = side2;
}
}
if (selected.length < 6) {
for (i = 0; i < 4; i++) {
projection[i] = getPointParallelProjection(selected[i]);
}
projection[4] = 'rgb(0,0,0)';
}
}
return projection;
}
// Параллельная проекция точки
function getPointParallelProjection(point) {
return {
x:point.x,
y:point.y + point.z / 4};
}
<canvas id="animation" width="300" height="300">
<p>Your browser does not support Canvas</p>
</canvas>