笛卡尔坐标和屏幕坐标之间的转换
Translating between cartesian and screen coordinates
对于我的游戏,我需要在两个坐标系之间转换的函数。这主要是数学问题,但我需要的是C++代码来做这件事,并解释如何解决我的问题。
屏幕坐标:
a) 左上角为0,0
b) 无负值
c) 右+=x(x值越多,右边的点越多)
d) 底部+=y
笛卡尔二维坐标:
a) 中点是(0,0)
b) 负值确实存在
c) 右侧+=x
d) bottom-=y(y越小,底部的点越多)
我需要一种简单的方法来从一个系统转换到另一个系统,反之亦然。要做到这一点,(我想)我需要一些知识,比如笛卡尔坐标中的(0,0)[屏幕坐标的左上角]在哪里。
然而,有一个问题是,对于笛卡尔坐标中的某个点,在将其转换为屏幕坐标后,屏幕坐标中的位置可能是负的,这是无稽之谈。我不能把屏幕左上角的坐标放在(-inifity,+infinity)笛卡尔坐标。。。
我该如何解决这个问题?我能想到的唯一解决方案是将屏幕(0,0)放在笛卡尔(0,O)中,并且只使用笛卡尔系统的IV四分之一,但在这种情况下,使用笛卡尔系统是毫无意义的。。。
我确信有一些方法可以将屏幕坐标转换为笛卡尔坐标,反之亦然,但我在思考负值时犯了一些错误。
从笛卡尔坐标转换为屏幕坐标的基本算法是
screenX = cartX + screen_width/2
screenY = screen_height/2 - cartY
但正如你提到的,笛卡尔空间是无限的,而你的屏幕空间不是。这可以通过改变屏幕空间和笛卡尔空间之间的分辨率来轻松解决。上述算法使得笛卡尔空间中的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
您必须知道屏幕的大小才能转换
转换为笛卡尔坐标:
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;
您需要知道屏幕的宽度和高度。
然后你可以做:
cartX = screenX - (width / 2);
cartY = -(screenY - (height / 2));
和:
screenX = cartX + (width / 2);
screenY = -cartY + (height / 2);
您总是会遇到这样的问题,即结果可能不在屏幕上——要么是负值,要么是大于可用屏幕大小的值。
有时这并不重要:例如,如果图形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;
我为您提供了一些基于微软文章的boost c++: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;
}
- 构造函数和转换运算符之间的重载解析
- C ++中无符号位长度类型之间的隐式转换,即uint8_t,uint16_t
- 模板转换运算符在 clang 6 和 clang 7 之间的区别
- 派生类(构造函数具有参数)和基类(构造函数缺少参数)之间没有可行的转换
- Cxx.jl 在 Julia Complex 和 std::complex 之间进行转换
- 如何在 std::string 和 Aws::String 之间进行转换?
- 转换字符时Arduino DUE 和 Arduino UNO 之间的区别
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- 指向 POD 类型的指针之间的静态转换与重新解释转换
- 在 Rcpp 中的字符串类型之间转换时出错
- 如何声明不同类型的模板化类之间的转换
- C 和 C++ 中的函数指针转换之间的差异
- 与浮点转换之间的规范化整数
- 重新解释强制转换和 C 样式转换之间的 C++ 区别
- C++ get 和类型转换之间的用法有什么区别?我应该使用哪一个?
- printf函数参数之间的序列点;转换之间的顺序点是否重要
- Clang和GCC中不明确基类转换之间的行为差异
- 转换之间的双和字节数组,为传输ZigBee API
- 隐式转换和显式转换之间的区别
- interpret_cast和C样式强制转换之间的区别是什么