2013-02-14 32 views
8

Đối với trò chơi của tôi, tôi cần các chức năng để dịch giữa hai hệ tọa độ. Vâng đó là câu hỏi toán học chủ yếu nhưng những gì tôi cần là mã C++ để làm điều đó và một chút giải thích làm thế nào để giải quyết vấn đề của tôi.Dịch giữa các tọa độ giữa màn hình và tọa độ

coordiantes màn hình:

a) góc trên cùng bên trái là 0,0

b) không có giá trị trừ

c) đúng + = x (càng là x giá trị, càng có nhiều trên bên phải là điểm)

d) đáy + = y

Descartes 2D phối:

a) điểm giữa là (0, 0)

b) trừ đi giá trị thực sự tồn tại

c) đúng + = x

d) dưới - = y (ít là y, càng có nhiều ở phía dưới là điểm)

Tôi cần một cách dễ dàng để dịch từ hệ thống này sang hệ thống khác và ngược lại. Để làm điều đó, (tôi nghĩ) Tôi cần một số kiến ​​thức như ở đâu (0, 0) [góc trên cùng bên trái trong tọa độ màn hình] được đặt trong tọa độ Descartes. Tuy nhiên có một vấn đề mà đối với một số điểm trong tọa độ Descartes sau khi dịch nó sang màn hình, vị trí trong tọa độ màn hình có thể bị trừ, đó là một điều vô nghĩa. Tôi không thể đặt góc trên cùng bên trái của tọa độ màn hình trong (-inifity, + infinity) coes cartesian ...

Làm cách nào để giải quyết vấn đề này? Giải pháp duy nhất tôi có thể nghĩ là để đặt màn hình (0, 0) trong cartesian (0, 0) và chỉ sử dụng IV quý của hệ thống Descartes, nhưng trong trường hợp đó sử dụng hệ thống Descartes là vô nghĩa ...

I ' m chắc chắn có cách để dịch tọa độ màn hình vào tọa độ Descartes và ngược lại, nhưng tôi đang làm điều gì đó sai trái trong suy nghĩ của tôi với giá trị trừ.

+0

tọa độ màn hình ** là ** cartesian? khi nào nó trở thành phi cartes? – thang

+0

anh ta muốn có tọa độ âm – sgonzalez

+0

@thang trục Y khác nhau trên màn hình và chuyên đề. – user1873947

Trả lời

11

Các thuật toán cơ bản để dịch từ tọa độ Descartes đến tọa độ màn hình là

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

Nhưng như bạn đã đề cập, không gian Descartes là vô hạn, và không gian màn hình của bạn là không. Điều này có thể được giải quyết dễ dàng bằng cách thay đổi độ phân giải giữa không gian màn hình và không gian cartes. Thuật toán trên làm cho 1 đơn vị trong không gian Descartes = 1 đơn vị/pixel trong không gian màn hình. Nếu bạn cho phép các tỷ lệ khác, bạn có thể "thu phóng" ra hoặc trong không gian màn hình của bạn để bao gồm tất cả không gian Descartes cần thiết.

Điều này sẽ thay đổi thuật toán trên để

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

Bây giờ bạn xử lý tiêu cực (hoặc quá lớn) screenX và Screeny bằng cách sửa đổi yếu tố zoom của bạn cho đến khi tất cả các tọa độ Descartes của bạn sẽ phù hợp trên màn hình.

Bạn cũng có thể cho phép xoay không gian tọa độ, nghĩa là, cho phép trung tâm của không gian Descartes nằm ngoài trung tâm của màn hình. Điều này cũng có thể giúp cho phép zoom_factor của bạn ở mức chặt chẽ nhất có thể nhưng cũng phù hợp với dữ liệu không được phân phối đồng đều xung quanh nguồn gốc không gian Descartes.

Điều này sẽ thay đổi thuật toán để

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

Bạn cần biết chiều rộng và chiều cao của màn hình.

Sau đó, bạn có thể làm:

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

Và:

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

dude, tại sao bạn rất cẩu thả? tại sao bạn có chiều rộng cho cả x và y? – thang

2

Bạn phải biết kích thước của màn hình để có thể chuyển đổi

Convert to Descartes:

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

Chuyển đổi sang màn hình:

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

Đối với trường hợp bạn có một giá trị màn hình tiêu cực: tôi sẽ không lo lắng về điều này, nội dung này sẽ chỉ đơn giản là được cắt bớt vì vậy người dùng sẽ không nhìn thấy. Nếu điều này một vấn đề, tôi sẽ thêm một số ràng buộc ngăn cản tọa độ Descartes quá lớn.Một giải pháp khác, vì bạn không thể có các cạnh là +/- vô cùng, sẽ là mở rộng tọa độ của bạn (ví dụ: 1 pixel = 10 Descartes) Hãy gọi số này scalefactor. Các phương trình bây giờ là:

Convert to Descartes với yếu tố quy mô:

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

Chuyển đổi Screen với yếu tố quy mô:

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

Bạn sẽ luôn luôn có những vấn đề mà kết quả có thể được ra khỏi màn hình - dưới dạng giá trị âm hoặc giá trị lớn hơn kích thước màn hình có sẵn.

Đôi khi điều đó không quan trọng: ví dụ: nếu API đồ họa của bạn chấp nhận các giá trị âm và hãy kẹp bản vẽ của bạn cho bạn. Đôi khi nó sẽ quan trọng, và đối với những trường hợp đó bạn nên có một chức năng kiểm tra nếu một tập hợp các tọa độ màn hình nằm trên màn hình.

Bạn cũng có thể viết các chức năng cắt riêng của mình để thực hiện điều gì đó hợp lý với tọa độ rơi ra khỏi màn hình (chẳng hạn như cắt xén tọa độ màn hình phủ định thành 0 và tọa độ quá lớn so với tọa độ tối đa trên màn hình). Tuy nhiên, hãy nhớ rằng "hợp lý" phụ thuộc vào những gì bạn đang cố gắng làm, vì vậy tốt nhất là nên giữ các chức năng như vậy cho đến khi bạn thực sự cần chúng.


Trong mọi trường hợp, như câu trả lời khác đã lưu ý, bạn có thể chuyển đổi giữa các hệ thống phối hợp như:

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

tôi đã có một số tăng C++ cho bạn, dựa trên bài viết microsoft: https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx

Bạn chỉ cần biết hai điểm màn hình và hai điểm trong hệ tọa độ của bạn.Sau đó, bạn có thể chuyển đổi điểm từ hệ thống này sang hệ thống khác.

#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; 
}