2013-02-14 21 views
8

Do mojej gry potrzebuję funkcji do tłumaczenia między dwoma układami współrzędnych. Cóż, to głównie pytanie matematyczne, ale potrzebuję tego kodu C++ i wyjaśnienia, jak rozwiązać mój problem.Tłumaczenie współrzędnych kartezjańskich i ekranowych

ekranu coordiantes:

a) lewy górny róg jest 0,0

b) bez wartości minus

C) bezpośrednio + = x (im więcej jest wartość X, tym więcej na prawo to punkt)

d) dolny + = Y

współrzędne kartezjańskie

2D:

a) punkt środkowy jest (0, 0)

b) bez wartości istnieją

C) w prawo + = X

d) dolny - = r (mniej y, tym bardziej w na dole jest punkt)

Potrzebuję łatwego sposobu na przetłumaczenie z jednego systemu na inny i odwrotnie. Aby to zrobić (myślę) potrzebuję wiedzy, np. Gdzie jest (0, 0) [lewy górny róg w współrzędnych ekranu] umieszczonych we współrzędnych kartezjańskich.

Istnieje jednak problem, że dla pewnego punktu we współrzędnych kartezjańskich po przetłumaczeniu go na ekrany, pozycja na współrzędnych ekranu może być ujemna, co jest nonsensem. Nie mogę umieścić lewego górnego rogu współrzędnych ekranu w (-ififity, + nieskończoność) kartezjańskich współrzędnych ...

Jak mogę to rozwiązać? Jedyne rozwiązanie, jakie mogę wymyślić to umieszczenie ekranu (0, 0) w kartezjańskim (0, 0) i używać tylko czwartej ćwiartki systemu kartezjańskiego, ale w takim przypadku użycie systemu kartezjańskiego jest bezcelowe ...

Ja " Jestem pewien, że istnieją sposoby tłumaczenia współrzędnych ekranu na współrzędne kartezjańskie i odwrotnie, ale robię coś złego w moim myśleniu z tymi wartościami ujemnymi.

+0

Współrzędna ekranu ** to ** kartezjański? kiedy stało się niekartezjańskie? – thang

+0

chce mieć ujemne współrzędne – sgonzalez

+0

@thang oś Y jest inna na ekranie i kartezjańskim. – user1873947

Odpowiedz

11

Podstawowy algorytm do przetłumaczenia z kartezjańskim układzie współrzędnych Współrzędne ekranowe to

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

Ale jak wspomniano, przestrzeń kartezjańska jest nieskończona, a przestrzeń na ekranie nie jest. Można to łatwo rozwiązać, zmieniając rozdzielczość między przestrzenią ekranu a przestrzenią kartezjańską. Powyższy algorytm tworzy 1 jednostkę w przestrzeni kartezjańskiej = 1 jednostkę/piksel w przestrzeni ekranu. Jeśli zezwolisz na inne współczynniki, możesz "powiększyć" lub na swoim ekranie, aby pokryć całą niezbędną przestrzeń kartezjańską.

To byłoby zmienić powyższy algorytm

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

teraz obsługiwać ujemne (lub zbyt duże) screenX i Screeny modyfikując swój współczynnik powiększenia aż do wszystkich współrzędnych kartezjańskich zmieści się na ekranie.

Można również zezwolić na panoramowanie przestrzeni współrzędnych, co oznacza, że ​​centrum przestrzeni kartezjańskiej może znajdować się poza środkiem ekranu. Może to również pomóc w umożliwieniu maksymalizacji współczynnika zoom_factor, ale także dopasować dane, które nie są równomiernie rozmieszczone wokół miejsca pochodzenia kartezjańskiego.

to zmieni algorytm

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

Musisz znać szerokość i wysokość ekranu.

Następnie można zrobić:

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

I:

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

stary, dlaczego jesteś taki niechlujny? dlaczego masz szerokość zarówno dla x, jak i dla y? – thang

2

Musisz znać rozmiar ekranu, aby móc konwertować

Konwersja do kartezjański:

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

Konwersja na ekranie:

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

W przypadkach, gdzie masz ujemną wartość ekranie: Nie martwiłbym się o to, ta zawartość zostanie po prostu obcięty więc użytkownik nie będzie widać. Jeśli ten problem to , dodam pewne ograniczenia, które zapobiegną zbyt dużemu współrzędnemu kartezjańskiemu.Innym rozwiązaniem, ponieważ nie możesz mieć krawędzi o +/- nieskończoności, byłoby skalowanie twoich współrzędnych (np. 1 piksel = 10 kartezjański) Nazwijmy to scalefactor. Równania są teraz:

Konwersja do kartezjańskiego ze współczynnikiem skali:

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

Konwersja do ekranu ze współczynnikiem skali:

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

zawsze będziesz miał problem, że wynik mógłby być wyłączony ekran - jako wartość ujemna lub jako wartość większa niż dostępny rozmiar ekranu.

Czasami to nie ma znaczenia: np. Jeśli interfejs API graficznego akceptuje wartości ujemne i klipuje je za Ciebie. Czasami będzie to miało znaczenie, a dla tych przypadków powinieneś mieć funkcję, która sprawdza, czy zestaw współrzędnych ekranu jest na ekranie.

Można również napisać własne funkcje przycinania, które próbują zrobić coś sensownego z współrzędnymi, które wypadają poza ekranem (np. Obcięcie ujemnych współrzędnych ekranu do 0 i współrzędnych, które są zbyt duże do maksymalnej współrzędnej na ekranie). Należy jednak pamiętać, że "uzasadnione" zależy od tego, co próbujesz zrobić, więc najlepiej będzie wstrzymać się od zdefiniowania takich funkcji, dopóki ich nie potrzebujesz.


W każdym razie, jak inne odpowiedzi zauważyli, można konwertować pomiędzy układami współrzędnych jako:

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

i

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

mam jakiś impuls C++ dla ciebie, w oparciu o Microsoft artykułu: https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx

Trzeba tylko wiedzieć, dwa punkty ekranem i dwa punkty twój układ współrzędnych.Następnie możesz przekonwertować punkt z jednego systemu na inny.

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