Перевод между декартовой и экранной координатами

Для моей игры мне нужны функции для перевода между двумя системами координат. Ну, это в основном математический вопрос, но мне нужен код C ++, чтобы сделать это, и немного объяснения, как решить мою проблему.

Координаты экрана:

а) верхний левый угол 0,0

б) нет минус значений

в) вправо + = х (чем больше значение х, тем больше справа точка)

г) снизу + = у

Декартовы 2D координаты:

а) средняя точка (0, 0)

б) минус значения существуют

в) правый + = х

г) дно — = у (чем меньше у, тем больше у дна точка)

Мне нужен простой способ перевода из одной системы в другую и наоборот. Чтобы сделать это, (я думаю) мне нужны некоторые знания, например, где находится (0, 0) [верхний левый угол в экранных координатах] в декартовых координатах.

Однако существует проблема, заключающаяся в том, что для некоторой точки в декартовых координатах после перевода ее в экранные координаты позиция в экранных координатах может быть минусовой, что является бессмыслицей. Я не могу поместить верхний левый угол координат экрана в (-inifity, + infinity) декартовых координат …

Как я могу решить это? Единственное решение, которое я могу придумать, это поместить экран (0, 0) в декартову (0, 0) и использовать только четверть декартовой системы IV, но в этом случае использование декартовой системы не имеет смысла …

Я уверен, что есть способы перевода экранных координат в декартовы координаты и наоборот, но я ошибаюсь, думая об этом минус значения.

9

Решение

Основной алгоритм перевода из декартовых координат в экранные координаты

screenX = cartX + screen_width/2
screenY = screen_height/2 - cartY

Но, как вы упомянули, декартово пространство бесконечно, а пространство экрана — нет. Это можно легко решить, изменив разрешение между пространством экрана и декартовым пространством. Приведенный выше алгоритм составляет 1 единицу в декартовом пространстве = 1 единицу / пиксель в пространстве экрана. Если вы учитываете другие соотношения, вы можете «уменьшить» или на экране, чтобы покрыть все необходимое декартово пространство.

Это изменит вышеуказанный алгоритм на

screenX = zoom_factor*cartX + screen_width/2
screenY = screen_height/2 - zoom_factor*cartY

Теперь вы обрабатываете негативные (или слишком большие) screenX и screenY, изменяя коэффициент масштабирования, пока все ваши декартовы координаты не уместятся на экране.

Вы также можете разрешить панорамирование координатного пространства, что означает, что центр декартового пространства находится вне центра экрана. Это также может помочь в том, чтобы ваш zoom_factor оставался как можно более узким, а также вмещать данные, которые неравномерно распределены вокруг источника декартового пространства.

Это изменит алгоритм на

screenX = zoom_factor*cartX + screen_width/2 + offsetX
screenY = screen_height/2 - zoom_factor*cartY + offsetY
12

Другие решения

Вы должны знать размер экрана, чтобы иметь возможность конвертировать

Преобразовать в декартову:

cartesianx = screenx - screenwidth / 2;
cartesiany = -screeny + screenheight / 2;

Преобразовать в экран:

screenx = cartesianx + screenwidth / 2;
screeny = -cartesiany + screenheight / 2;

Для случаев, когда у вас отрицательное значение экрана:
Я не буду беспокоиться об этом, этот контент будет просто обрезан, чтобы пользователь не видел. Если это является проблема, я бы добавил некоторые ограничения, которые препятствуют слишком большой декартовой координате. Другое решение, поскольку вы не можете иметь края +/- бесконечность, было бы масштабировать ваши координаты (например, 1 пиксель = 10 декартовых). Давайте назовем это scalefactor, Уравнения теперь:

Преобразовать в декартову с масштабным коэффициентом:

cartesianx = scalefactor*screenx - screenwidth / 2;
cartesiany = -scalefactor*screeny + screenheight / 2;

Преобразовать в экран с масштабным коэффициентом:

screenx = (cartesianx + screenwidth / 2) / scalefactor;
screeny = (-cartesiany + screenheight / 2) / scalefactor;
2

Вам нужно знать ширину и высоту экрана.

Тогда вы можете сделать:

cartX =   screenX - (width / 2);
cartY = -(screenY - (height / 2));

А также:

screenX =  cartX + (width / 2);
screenY = -cartY + (height / 2);
1

У вас всегда будет проблема с тем, что результат может быть вне экрана — либо как отрицательное значение, либо как значение, превышающее доступный размер экрана.

Иногда это не имеет значения: например, если ваш графический API принимает отрицательные значения и обрезает ваш чертеж для вас. Иногда это имеет значение, и для этих случаев у вас должна быть функция, которая проверяет, есть ли на экране набор координат экрана.

Вы также можете написать свои собственные функции отсечения, которые пытаются сделать что-то разумное с координатами, которые падают с экрана (например, усечение отрицательных экранных координат до 0 и координат, которые слишком велики для максимальной экранной координаты). Тем не менее, имейте в виду, что «разумный» зависит от того, что вы пытаетесь сделать, поэтому может быть лучше не задавать такие функции, пока они вам действительно не понадобятся.


В любом случае, как отмечали другие ответы, вы можете выполнить преобразование между системами координат следующим образом:

cart.x = screen.x - width/2;
cart.y = height/2 - screen.y;

а также

screen.x = cart.x + width/2;
screen.y = height/2 - cart.y;
1

У меня есть кое-что для поддержки C ++, основанное на статье Microsoft:
https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx

Вам просто нужно знать две точки экрана и две точки в вашей системе координат. Затем вы можете преобразовать точку из одной системы в другую.

#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>

/* Matrix inversion routine.
Uses lu_factorize and lu_substitute in uBLAS to invert a matrix */
template<class T>
bool InvertMatrix(const boost::numeric::ublas::matrix<T>& input, boost::numeric::ublas::matrix<T>& inverse)
{
typedef boost::numeric::ublas::permutation_matrix<std::size_t> pmatrix;

// create a working copy of the input
boost::numeric::ublas::matrix<T> A(input);

// create a permutation matrix for the LU-factorization
pmatrix pm(A.size1());

// perform LU-factorization
int res = lu_factorize(A, pm);
if (res != 0)
return false;

// create identity matrix of "inverse"inverse.assign(boost::numeric::ublas::identity_matrix<T> (A.size1()));

// backsubstitute to get the inverse
lu_substitute(A, pm, inverse);

return true;
}

PointF ConvertCoordinates(PointF pt_in,
PointF pt1, PointF pt2, PointF pt1_, PointF pt2_)
{

float matrix1[]={
pt1.X,           pt1.Y,           1.0f,           0.0f,
-pt1.Y,           pt1.X,           0.0f,           1.0f,
pt2.X,           pt2.Y,           1.0f,           0.0f,
-pt2.Y,           pt2.X,           0.0f,           1.0f
};

boost::numeric::ublas::matrix<float> M(4, 4);
CopyMemory(&M.data()[0], matrix1, sizeof(matrix1));

boost::numeric::ublas::matrix<float> M_1(4, 4);
InvertMatrix<float>(M, M_1);

double vector[] = {
pt1_.X,
pt1_.Y,
pt2_.X,
pt2_.Y
};

boost::numeric::ublas::vector<float> u(4);
boost::numeric::ublas::vector<float> u1(4);
u(0) = pt1_.X;
u(1) = pt1_.Y;
u(2) = pt2_.X;
u(3) = pt2_.Y;

u1 = boost::numeric::ublas::prod(M_1, u);

PointF pt;
pt.X = u1(0)*pt_in.X + u1(1)*pt_in.Y + u1(2);
pt.Y = u1(1)*pt_in.X - u1(0)*pt_in.Y + u1(3);
return pt;
}
0
По вопросам рекламы [email protected]