2013-02-14 61 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; 
}