Translation between Cartesian and screen coordinates

For my game, I need functions to translate between two coordinate systems. Well, this is basically a math question, but I need C ++ code for this and a bit of explanation on how to solve my problem.

Screen coordinates:

a) upper left corner 0,0

b) no negative values

c) right + = x (the larger the value of x, the greater the point on the right)

d) bottom + = y

Cartesian 2D coordinates:

a) midpoint (0, 0)

b) there are minus values

c) right + = x

d) bottom - = y (the less y, the more at the lower point)

I need a simple way to transfer from one system to another and vice versa. For this (I think) I need some knowledge, for example, where is (0, 0) [the upper left corner in the coordinates of the screen] located in Cartesian coordinates.

However, there is a problem that for a certain point in Cartesian coordinates, after translating it into screen coordinates, the position in the screen coordinates may be minus, which is nonsense. I can’t put the top left corner of the screen coordinate in (-inifity, + infinity) Cartesian coordinates ...

How can i solve this? The only solution I can think of is to place the screen (0, 0) in a Cartesian (0, 0) and use only a quarter of the Cartesian system, but in this case using a Cartesian system is pointless ...

I am sure that there are ways to translate the screen coordinates into Cartesian coordinates and vice versa, but I'm doing something wrong in my thoughts with these minus values.

+8
c ++ math algorithm coordinates coordinate-systems
source share
5 answers

The basic algorithm for translating from Cartesian coordinates to screen coordinates

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

But, as you mentioned, Cartesian space is infinite, but your screen space is not. This can be easily solved by changing the resolution between the screen space and the Cartesian space. The above algorithm makes 1 unit in Cartesian space = 1 unit / pixel in screen space. If you allow other coefficients, you can “scale” either on the screen to cover all the necessary Cartesian space.

This will change the above algorithm to

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

Now you are processing the negative (or too large) screenX and screenY, changing the scaling factor until all your Cartesian coordinates fit on the screen.

You can also enable panning of the coordinate space, which means that the center of the Cartesian space will be outside the center of the screen. It can also help keep your zoom_factor as dense as possible, but also select data that is evenly distributed around the origin of the Cartesian space.

This will change the algorithm to

 screenX = zoom_factor*cartX + screen_width/2 + offsetX screenY = screen_height/2 - zoom_factor*cartY + offsetY 
+11
source share

You must know the screen size in order to be able to convert

Convert to Cartesian:

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

Convert to Screen:

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

In cases where you have a negative screen value: I would not worry about this, this content will simply be cropped so that the user does not see it. If this is a problem, I would add some restrictions that prevent the Cartesian coordinate from being too large. Another solution, since you cannot have edges +/- infinity, would be scaling your coordinates (e.g. 1 pixel = 10 Cartesian). Call this scalefactor . Equations now:

Convert to Cartesian with scale factor:

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

Convert to screen with scale factor:

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

You need to know the width and height of the screen.

Then you can do:

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

and

 screenX = cartX + (width / 2); screenY = -cartY + (height / 2); 
+1
source share

You will always have a problem that the result can be disconnected from the screen - either as a negative value, or as a value larger than the size of the available screen.

Sometimes it doesn’t matter: for example, if your graphic API accepts negative values ​​and consolidates your drawing for you. Sometimes it matters, and for these cases you should have a function that checks for a set of screen coordinates on the screen.

You can also write your own clipping functions that try to do something reasonable with coordinates that fall from the screen (for example, cropping negative screen coordinates to 0 and coordinates that are too large for the maximum screen coordinate). However, keep in mind that “reasonable” depends on what you are trying to do, so it would be better to dwell on defining such functions until they need you.


In any case, as the other answers noted, you can convert between coordinate systems as:

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

and

 screen.x = cart.x + width/2; screen.y = height/2 - cart.y; 
+1
source share

I have some C ++ boost for you, based on a Microsoft article: https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx

You just need to know two points on the screen and two points in your coordinate system. Then you can convert the point from one system to another.

 #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; } 
0
source share

All Articles