2-point perspective via angles

Rather than using straight horizontal & vertical, it now snaps
to lines with the same slope as the two vanishing points
(the horizon chosen by the user), and lines perpendicular to that.

Note - Still need guides during drag.  Also, there's a bug when
calculating slope that causes the line to go way off in the
opposite direction, which needs addressing.
This commit is contained in:
Bill Kendrick 2023-12-21 02:22:07 -08:00
parent e9db3d2393
commit 05b76c8b5f

View file

@ -17,6 +17,8 @@
#include "SDL_image.h"
#include "SDL_mixer.h"
#define SNAP 10
enum
{
@ -79,7 +81,7 @@ int a1_pt_x, a1_pt_y;
int a2_pt_x[2], a2_pt_y[2], a2_pt_cur;
int a3_pt_x[3], a3_pt_y[3], a3_pt_cur;
int line_start_x, line_start_y;
float a2_valid_angle[8];
/* Function prototypes: */
Uint32 n_pt_persp_api_version(void);
@ -276,6 +278,17 @@ void n_pt_persp_click(magic_api * api, int which, int mode ATTRIBUTE_UNUSED,
/* Set next position of 2-point perspective */
a2_pt_x[a2_pt_cur] = x;
a2_pt_y[a2_pt_cur] = y;
if (abs(a2_pt_x[0] - a2_pt_x[1]) < SNAP) {
if (a2_pt_x[0] <= a2_pt_x[1]) {
a2_pt_x[0] -= (SNAP / 2);
a2_pt_x[1] += (SNAP / 2);
} else {
a2_pt_x[0] += (SNAP / 2);
a2_pt_x[1] -= (SNAP / 2);
}
}
a2_pt_cur = (a2_pt_cur + 1) % 2;
} else if (which == TOOL_3PT_SELECT) {
/* Set next position of 3-point perspective */
@ -286,6 +299,34 @@ void n_pt_persp_click(magic_api * api, int which, int mode ATTRIBUTE_UNUSED,
/* Start drawing a line */
SDL_BlitSurface(canvas, NULL, n_pt_persp_snapshot, NULL);
if (which == TOOL_2PT_DRAW) {
int i;
/* Horizon between vanishing points, and perpendicular (rise above/below) */
a2_valid_angle[0] = atan2(a2_pt_y[1] - a2_pt_y[0], a2_pt_x[1] - a2_pt_x[0]);
a2_valid_angle[1] = a2_valid_angle[0] + M_PI;
a2_valid_angle[2] = a2_valid_angle[0] + (M_PI / 2.0);
a2_valid_angle[3] = a2_valid_angle[0] + (M_PI / 2.0) + M_PI;
/* Angles that point toward the two vanishing points */
if (x == a2_pt_x[0]) {
x++;
}
if (x == a2_pt_x[1]) {
x++;
}
a2_valid_angle[4] = atan2(a2_pt_y[0] - y, a2_pt_x[0] - x);
a2_valid_angle[5] = a2_valid_angle[4] + M_PI;
a2_valid_angle[6] = atan2(a2_pt_y[1] - y, a2_pt_x[1] - x);
a2_valid_angle[7] = a2_valid_angle[6] + M_PI;
for (i = 0; i < 8; i++) {
if (a2_valid_angle[i] > M_PI) {
a2_valid_angle[i] -= (M_PI * 2);
}
}
}
line_start_x = x;
line_start_y = y;
n_pt_persp_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
@ -342,8 +383,6 @@ void n_pt_persp_drag(magic_api * api, int which,
}
}
#define SNAP 10
void n_pt_persp_work(magic_api * api, int which,
SDL_Surface * canvas, int x, int y,
SDL_Rect * update_rect, int xor)
@ -400,54 +439,54 @@ void n_pt_persp_work(magic_api * api, int which,
}
} else if (which == TOOL_2PT_DRAW) {
/* 2-point perspective */
int i, best_angle_idx;
float cursor_angle, diff, best_diff;
/* Find the valid angle that the drawn angle fits best to */
cursor_angle = atan2f(y - line_start_y, x - line_start_x);
best_angle_idx = -1;
best_diff = M_PI * 2;
for (i = 0; i < 8; i++) {
diff = fabs(cursor_angle - a2_valid_angle[i]);
if (diff < best_diff) {
best_angle_idx = i;
best_diff = diff;
}
}
if (best_angle_idx == -1) {
printf("???\n");
return;
}
/* Calculate a line segment, so we can determine the slope */
x1 = line_start_x;
y1 = line_start_y;
x2 = line_start_x + cos(a2_valid_angle[best_angle_idx]) * 1000;
y2 = line_start_y + sin(a2_valid_angle[best_angle_idx]) * 1000;
if (abs(line_start_x - x) <= SNAP) {
/* Vertical */
x2 = x1;
y2 = y;
} else if (abs(line_start_y - y) <= SNAP) {
/* Horizontal */
// printf("angle #%d (%d)\n", best_angle_idx, (int) (a2_valid_angle[best_angle_idx] * 180.0 / M_PI));
if (x2 != x1) {
slope = ((float) y2 - (float) y1) / ((float) x2 - (float) x1);
x2 = x;
y2 = y1;
} else {
int ok, i;
y2 = line_start_y + (slope * (x - line_start_x));
/* Diagonal */
ok = 0;
for (i = 0; i < 2 && ok == 0; i++) {
slope = ((float) y1 - (float) a2_pt_y[i]) / ((float) x1 - (float) a2_pt_x[i]);
x2 = x;
y2 = line_start_y + (slope * (x - line_start_x));
/* Don't go past our cursor's Y */
if ((y < line_start_y && y2 < y) ||
(y > line_start_y && y2 > y)) {
if (slope != 0.0) {
y2 = y;
x2 = ((y - line_start_y) / slope) + line_start_x;
}
}
/* Wrong side? Use the point 2 */
slope2 = ((float) line_start_y - (float) y) / ((float) line_start_x - (float) x);
if ((slope2 > 0.00 && slope < 0.00) ||
(slope2 < 0.00 && slope > 0.00)) {
ok = 0;
if (i == 1) {
/* Worst case, snap to horizontal */
x2 = x;
y2 = y1;
}
} else {
ok = 1;
/* Don't go past our cursor's Y */
if ((y < line_start_y && y2 < y) ||
(y > line_start_y && y2 > y)) {
if (slope != 0.0) {
y2 = y;
x2 = ((y - line_start_y) / slope) + line_start_x;
}
}
/* FIXME: Sometimes the line goes off in the wrong direction! */
} else {
x2 = x;
y2 = y;
}
} else if (which == TOOL_3PT_DRAW) {
/* 3-point perspective */