"Зеркальное отображение" объекта PShape (проблема ротации/перевода) с помощью Processing

58
6

Я хотел бы "отразить" объект PShape, как на картинке ниже:

https://i.imgur.com/kwTQ7vA.png

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

enter image description here

Я пытался вычислить угол с первыми 2 вершинами исходной формы (неправильный четырехугольник) и функцией atan2() но безрезультатно.

Я был бы очень признателен, если бы кто-то помог понять, как решить эту проблему.

int W = 20;
int H = 20;
int D = 20;

PShape object;

void setup(){
size(600, 600, P2D);
smooth();

}

void draw(){
background(255);

pushMatrix();
translate(width/2, height/1.3);

int td = -1;
for (int i = 0; i < 6; i++){
translate(0, td*H*2);
scale(-1, 1);
rotate(PI);
object();
td *= -1;
}

popMatrix();

}

void object() {
beginShape(QUADS);

vertex(-20, 20);
vertex(20, 0);
vertex(20, -20);
vertex(-20, -20);

endShape();
}

спросил(а) 2019-01-03T02:28:00+03:00 1 год, 10 месяцев назад
1
Решение
80

Чтобы сделать то, что вы хотите, вы должны создать фигуру на 2 заданных угла для верхней и нижней части angleT и angleB. Начало координат (0,0) находится в центре фигуры. Это приводит к тому, что стержни для поворотов находятся в середине уклонов формы:

int W = 40;
int H = 40;
float angleT = -PI/18;
float angleB = PI/15;

PShape object;

void object() {

float H1 = -H/2 + W*tan(angleB);
float H2 = H/2 + W*tan(angleT);

beginShape(QUADS);

vertex(-W/2, -H/2);
vertex(W/2, H1);
vertex(W/2, H2);
vertex(-W/2, H/2);

endShape();
}

Когда вы рисуете части, вы должны различать четные и нечетные части. Детали необходимо перевернуть по горизонтали, перевернув ось Y (scale(1, -1)). angleB части должны быть повернуты на двойной angleB а нечетные части должны быть повернуты на angleT Для поворота центр склонов (осей) должен быть переведен в начало координат:

void setup(){
size(600, 600, P2D);
smooth();
}

void draw(){

background(255);

translate(width/2, height/2);

float HC1 = -H/2 + W*tan(angleB)/2;
float HC2 = H/2 + W*tan(angleT)/2;

for (int i = 0; i < 15; i++){

float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;

translate(0, -HC);
rotate(angle*2);
translate(0, -HC);

object();
scale(1, -1);
}
}

Алгоритм работает для любого угла, положительного и отрицательного, включая 0.

Этот алгоритм может быть улучшен. Предположим, у вас есть квад, определенный 4 точками (p0, p1, p2, p3):

float[] p0 = {10, 0};
float[] p1 = {40, 10};
float[] p2 = {60, 45};
float[] p3 = {0, 60};

PShape object;

void object() {
beginShape(QUADS);
vertex(p0[0], p0[1]);
vertex(p1[0], p1[1]);
vertex(p2[0], p2[1]);
vertex(p3[0], p3[1]);
endShape();
}

Вычислите минимум, максимум, центральную точку, опоры и углы:

float minX = min( min(p0[0], p1[0]), min(p2[0], p3[0]) );
float maxX = max( max(p0[0], p1[0]), max(p2[0], p3[0]) );
float minY = min( min(p0[1], p1[1]), min(p2[1], p3[1]) );
float maxY = max( max(p0[1], p1[1]), max(p2[1], p3[1]) );

float cptX = (minX+maxX)/2;
float cptY = (minY+maxY)/2;

float angleB = atan2(p1[1]-p0[1], p1[0]-p0[0]);
float angleT = atan2(p2[1]-p3[1], p2[0]-p3[0]);

float HC1 = p0[1] + (p1[1]-p0[1])*(cptX-p0[0])/(p1[0]-p0[0]);
float HC2 = p3[1] + (p2[1]-p3[1])*(cptX-p3[0])/(p2[0]-p3[0]);

Нарисуйте форму, как раньше:

for (int i = 0; i < 6; i++){

float angle = (i % 2 == 0) ? -angleB : -angleT;
float HC = (i % 2 == 0) ? HC1 : HC2;

translate(cptX, -HC);
rotate(angle*2);
translate(-cptX, -HC);

object();
scale(1, -1);
}

Другой подход - сложить фигуру с обеих сторон:

Для этого вам нужно знать высоту осей (HC1, HC2) и углы (angleB, angleT). Так что это может быть реализовано на основе обоих вышеупомянутых подходов.

Определите опорные точки и направления верхнего и нижнего края:

PVector dir1 = new PVector(cos(angleB), sin(angleB));
PVector dir2 = new PVector(cos(angleT), sin(angleT));
PVector pv1 = new PVector(0, HC1); // or PVector(cptX, HC1)
PVector pv2 = new PVector(0, HC2); // or PVector(cptX, HC2)

Вычислите точку пересечения (X) обоих ребер. Конечно, это будет работать, только если
края не параллельны:

PVector v12  = pv2.copy().sub(pv1);
PVector nDir = new PVector(dir2.y, -dir2.x);
float d = v12.dot(nDir) / dir1.dot(nDir);
PVector X = pv1.copy().add( dir1.copy().mult(d) );

Алгоритм стека работает следующим образом:

for (int i = 0; i < 8; i++){

float fullAngle = angleT-angleB;

float angle = fullAngle * floor(i/2);
if ((i/2) % 2 != 0)
angle += fullAngle;
if (i % 2 != 0)
angle = -angle;

float flip = 1.0;
if (i % 2 != 0)
flip *= -1.0;
if ((i/2) % 2 != 0)
flip *= -1.0;

pushMatrix();

translate(X.x, X.y);
rotate(angle);
scale(1, flip);
rotate(-angleB);
translate(-X.x, -X.y);

object();

popMatrix();
}

ответил(а) 2019-01-03T11:05:00+03:00 1 год, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема