2013-02-14 182 views
8

对于我的游戏,我需要在两个坐标系之间进行转换的函数。那么这主要是数学问题,但我需要的是C++代码来做到这一点,并解释了如何解决我的问题。笛卡尔和屏幕坐标之间的转换

屏幕coordiantes:

一个)左上角是0,0

b)中没有负值

c)中右+ = X(越为x值,在越右是点)

d)底部+ = Y

笛卡尔二维坐标:

一个)中间点是(0,0)

b)中减去的值确实存在

c)中右+ = X

d)底部 - = Y(少为y,在更底部是点)

我需要一种简单的方法来从一个系统转换到另一个,反之亦然。为此,(我认为)我需要一些知识,如位于笛卡尔坐标中的(0,0)[屏幕坐标中的左上角]。

但是,有一个问题,即在将笛卡尔坐标转换为屏幕坐标后,屏幕坐标中的位置可能是负值,这是无意义的。我不能把屏幕坐标的左上角放在(-inifity,+ infinity)笛卡尔坐标系中......

我该如何解决这个问题?我能想到的唯一解决方案是将屏幕(0,0)置于笛卡儿(0,0)中,并且仅使用IV四分之一笛卡尔系统,但在那种情况下使用笛卡尔系统是毫无意义的...

I'当然,有些方法可以将屏幕坐标转换为笛卡尔坐标,反之亦然,但是我在考虑这个负值时做错了什么。

+0

屏幕坐标**是**笛卡儿?它何时成为非笛卡尔? – thang 2013-02-14 17:36:19

+0

他想要有负坐标 – sgonzalez 2013-02-14 17:36:49

+0

@thang Y轴在屏幕和笛卡儿中是不同的。 – user1873947 2013-02-14 17:44:10

回答

11

的基本算法,从笛卡尔坐标转换屏幕坐标是

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 
1

您需要知道屏幕的宽度和高度。

然后,你可以这样做:

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

和:

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

老兄,你为什么这么sl??为什么你对x和y都有宽度? – thang 2013-02-14 17:39:14

2

你必须知道屏幕的尺寸,以便能够转换

转换成直角坐标:

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

转换为屏幕:

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

对于您有负面的屏幕值情况: 我不担心这个,这个内容将简单地剪切,因此用户不会看到。如果这个的问题,我会添加一些约束,防止笛卡尔坐标太大。另一个解决方案,因为你的边不能是+/-无穷大,所以你的坐标就是缩放(例如1像素= 10笛卡尔)。我们称之为scalefactor。方程现在是:

转换为与比例因子直角坐标:

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

你将永远有问题,其结果可能是关闭的:

cartesianx = scalefactor*screenx - screenwidth/2; 
cartesiany = -scalefactor*screeny + screenheight/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; 
0

我已经有了一些提升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; 
}