Mouse coordinates to grid coordinates within an isometric map












4














I wrote an algorithm to transform mouse screen coordinates within an isometric map to corresponding coordinates of an underlying 2D-square grid. The algorithm works and I tested it successfully. I wanted to post it here so interested people could maybe check the algorithm and see if I can make any optimizations beyond of what I did already. My goal is to make the algorithm as compact as possible. There maybe are some smart mathematical solutions I didn't think of to save some lines of code or make it faster.



The input data for the rendering of the map is a simple 2D-array like:



0,0,0,0

0,0,0,0

0,0,0,0

...


Here is a screenshot of what the map looks like when rendered. It is not really a map right now but more of an outlining of the tiles I will render. The red coordinates are x and y values of the underlying source grid.



enter image description here



It is rendered with a zig-zag approach with an origin outside of the screen (top left). It is rendered row by row from left to right whereby every uneven row is inset by half a tiles width. This is a common approach to avoid having to fill the source 2D-grid with "zombie-data" if one would render it in a diamond approach.



What the algorithm does is:




  • the screen is logically divided into square rectangles with a width of my tile width and height of my tile height, i.e. 128px by 64px

  • the mouse coordinates are scaled by tile width and tile height and then floored. This determines in which screen rectangle the user clicked

  • then the mouse coordinates are compared against the center coordinates of this rectangle

  • regarding this result, a right angled triangle is calculated to check if the user clicked within a certain area of the rectangle. I am using the cosine of this triangle to compare against my initial rotation angle of 26,565 (atan of 0.5). This is the angle in which the sides of the rendered rhombi are rotated to achieve a 2:1 ratio of width and height (classic isometric projection for video games).

  • regarding on where the user clicked


    • the y value is determined from a lower and upper boundary

    • the x value is determined based on y being even or uneven




To run this code, you will need SDL2-2.0.9 and boost 1.67.0. to run. I am using MS Visual Studio Community 2017 as an IDE.



#include <iostream>
#include <vector>
#include <SDL.h>
#include <SDL_Image.h>
#include <boost/cast.hpp>

struct Point
{
std::size_t x;
std::size_t y;
};

Point mouseToGrid(int pMouseXPos, int pMouseYPos, std::size_t pTileWidth, std::size_t pTileHeight, const double PI, const int SCREEN_WIDTH, const int SCREEN_HEIGHT)
{
double mouseXPos = boost::numeric_cast<double>(pMouseXPos);
double mouseYPos = boost::numeric_cast<double>(pMouseYPos);
double tileWidth = boost::numeric_cast<double>(pTileWidth);
double tileHeight = boost::numeric_cast<double>(pTileHeight);
double tileWidthHalf = tileWidth / 2;
double tileHeightHalf = tileHeight / 2;

double mouseTileYPos = mouseYPos / tileHeight;
mouseTileYPos = std::floor(mouseTileYPos);

int screenRectCenterX = ((std::floor((mouseXPos / tileWidth))) * tileWidth) + tileWidthHalf;
int screenRectCenterY = (mouseTileYPos * tileHeight) + tileHeightHalf;

//determine lower and upper boundary for y
int minY = boost::numeric_cast<int>(2 * mouseTileYPos);
int maxY = boost::numeric_cast<int>((2 * mouseTileYPos) + 1);
if (mouseYPos >= screenRectCenterY)
{
minY = maxY;
maxY++;
}

//calc triangle sides in pixels
char mouseRectangleSector[2]{};
double opposite;
double adjacent;

if (mouseYPos >= screenRectCenterY)
{
mouseRectangleSector[0] = 'S';
opposite = mouseYPos - screenRectCenterY;
}
else
{
mouseRectangleSector[0] = 'N';
opposite = screenRectCenterY - mouseYPos;
}
if (mouseXPos >= screenRectCenterX)
{
mouseRectangleSector[1] = 'E';
adjacent = (screenRectCenterX + tileWidthHalf) - mouseXPos;
}
else{
mouseRectangleSector[1] = 'W';
adjacent = tileWidthHalf - (screenRectCenterX - mouseXPos);
}

double hypothenuse = std::sqrt(std::pow(opposite, 2) + std::pow(adjacent, 2));

//calculate cos and corresponding angle in rad and deg
double cos = adjacent / hypothenuse;
double angleRad = std::acos(cos);
double angleDeg = angleRad * 180 / PI;
//calculate initial rotation angle in rad and deg
double controlAtan = 0.5;
double controlAngleRad = std::atan(controlAtan);
double controlAngleDeg = controlAngleRad * 180 / PI;

//determine final position for y
if (mouseRectangleSector[0] == 'S')
{
if (angleRad > controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}
else
{
if (angleRad < controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}

//determine position for x
double mouseTileXPos;
if ((boost::numeric_cast<int>(mouseTileYPos)) % 2 == 0)
{
mouseTileXPos = (mouseXPos + tileWidthHalf) / tileWidth;
}
else
{
mouseTileXPos = mouseXPos / tileWidth;
}
mouseTileXPos = std::floor(mouseTileXPos);

Point gridXY{(std::size_t)mouseTileXPos, (std::size_t)mouseTileYPos};

return gridXY;
}

int main(int argc, char *args)
{
const double PI = 3.1415926535897932384626433832795;
const int SCREEN_WIDTH = 1600;
const int SCREEN_HEIGHT = 900;

//init SDL Components
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
return 1;
}

SDL_Window *sdlWindow = SDL_CreateWindow("A New Era", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

if (sdlWindow == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
return 1;
}

if (sdlRenderer == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

if (!(IMG_Init(IMG_INIT_PNG)))
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, SDL_ALPHA_OPAQUE);

//tile dimensions
std::size_t tileWidth = 128;
std::size_t tileHeight = 64;
std::size_t tileWidthHalf = tileWidth / 2;
std::size_t tileHeightHalf = tileHeight / 2;
int originX = 0;
int originY = 0;
int xScreenOffset;
int yScreenOffset = 0 - tileHeightHalf;

//add pseudo data points to tile vector
std::vector<Point> mapTiles{};

for (std::size_t y = 0; y < 10; y++)
{
for (std::size_t x = 0; x < 10; x++)
{
Point point{x, y};
mapTiles.push_back(point);
}
}

for (std::vector<Point>::iterator itPoint = mapTiles.begin(); itPoint < mapTiles.end(); itPoint++)
{
if (itPoint->y % 2 == 0)
{
xScreenOffset = 0;
}
else
{
xScreenOffset = tileWidthHalf;
}

//draw 2:1 rombus
std::size_t tileOriginX = itPoint->x * tileWidth;
std::size_t tileOriginY = itPoint->y * tileHeightHalf;
std::size_t x1 = tileOriginX + tileWidthHalf;
std::size_t y1 = tileOriginY + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, tileOriginX + originX + xScreenOffset, tileOriginY + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
std::size_t x = x1;
std::size_t y = y1;
x1 = x - tileWidthHalf;
y1 = y + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = x - tileWidthHalf;
y1 = y - tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = tileOriginX;
y1 = tileOriginY;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
}
SDL_RenderPresent(sdlRenderer);

//game loop
//control variables
SDL_Event event;
bool quit = false;

//originX = originX - tileWidthHalf;
while (!quit)
{
while (SDL_PollEvent(&event) != 0)
{
if (event.type == SDL_QUIT)
{
quit = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
int mouseXPos;
int mouseYPos;
SDL_GetMouseState(&mouseXPos, &mouseYPos);

Point gridCoordinates = mouseToGrid(mouseXPos, mouseYPos, tileWidth, tileHeight, PI, SCREEN_WIDTH, SCREEN_HEIGHT);
std::cout << "x,y : " << gridCoordinates.x << "," << gridCoordinates.y << std::endl;
}
}
}
}

SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 0;
}


As I said, the algorithm works so I don't need help getting it to run. I am looking for help or advice on how to make it more compact (reduce lines of code). Maybe I can get rid of a couple of if statements by doing some more maths. This is really the first time after my graduation I used this kind of maths in programming so there might be some tweaks that can be done.










share|improve this question









New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 3




    Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
    – tinstaafl
    Jan 1 at 17:17












  • I will add a fully functional example tomorrow, thank your for the advice
    – Tremah
    Jan 2 at 0:24










  • the code in my question is now a fully functional minimal example
    – Tremah
    2 days ago
















4














I wrote an algorithm to transform mouse screen coordinates within an isometric map to corresponding coordinates of an underlying 2D-square grid. The algorithm works and I tested it successfully. I wanted to post it here so interested people could maybe check the algorithm and see if I can make any optimizations beyond of what I did already. My goal is to make the algorithm as compact as possible. There maybe are some smart mathematical solutions I didn't think of to save some lines of code or make it faster.



The input data for the rendering of the map is a simple 2D-array like:



0,0,0,0

0,0,0,0

0,0,0,0

...


Here is a screenshot of what the map looks like when rendered. It is not really a map right now but more of an outlining of the tiles I will render. The red coordinates are x and y values of the underlying source grid.



enter image description here



It is rendered with a zig-zag approach with an origin outside of the screen (top left). It is rendered row by row from left to right whereby every uneven row is inset by half a tiles width. This is a common approach to avoid having to fill the source 2D-grid with "zombie-data" if one would render it in a diamond approach.



What the algorithm does is:




  • the screen is logically divided into square rectangles with a width of my tile width and height of my tile height, i.e. 128px by 64px

  • the mouse coordinates are scaled by tile width and tile height and then floored. This determines in which screen rectangle the user clicked

  • then the mouse coordinates are compared against the center coordinates of this rectangle

  • regarding this result, a right angled triangle is calculated to check if the user clicked within a certain area of the rectangle. I am using the cosine of this triangle to compare against my initial rotation angle of 26,565 (atan of 0.5). This is the angle in which the sides of the rendered rhombi are rotated to achieve a 2:1 ratio of width and height (classic isometric projection for video games).

  • regarding on where the user clicked


    • the y value is determined from a lower and upper boundary

    • the x value is determined based on y being even or uneven




To run this code, you will need SDL2-2.0.9 and boost 1.67.0. to run. I am using MS Visual Studio Community 2017 as an IDE.



#include <iostream>
#include <vector>
#include <SDL.h>
#include <SDL_Image.h>
#include <boost/cast.hpp>

struct Point
{
std::size_t x;
std::size_t y;
};

Point mouseToGrid(int pMouseXPos, int pMouseYPos, std::size_t pTileWidth, std::size_t pTileHeight, const double PI, const int SCREEN_WIDTH, const int SCREEN_HEIGHT)
{
double mouseXPos = boost::numeric_cast<double>(pMouseXPos);
double mouseYPos = boost::numeric_cast<double>(pMouseYPos);
double tileWidth = boost::numeric_cast<double>(pTileWidth);
double tileHeight = boost::numeric_cast<double>(pTileHeight);
double tileWidthHalf = tileWidth / 2;
double tileHeightHalf = tileHeight / 2;

double mouseTileYPos = mouseYPos / tileHeight;
mouseTileYPos = std::floor(mouseTileYPos);

int screenRectCenterX = ((std::floor((mouseXPos / tileWidth))) * tileWidth) + tileWidthHalf;
int screenRectCenterY = (mouseTileYPos * tileHeight) + tileHeightHalf;

//determine lower and upper boundary for y
int minY = boost::numeric_cast<int>(2 * mouseTileYPos);
int maxY = boost::numeric_cast<int>((2 * mouseTileYPos) + 1);
if (mouseYPos >= screenRectCenterY)
{
minY = maxY;
maxY++;
}

//calc triangle sides in pixels
char mouseRectangleSector[2]{};
double opposite;
double adjacent;

if (mouseYPos >= screenRectCenterY)
{
mouseRectangleSector[0] = 'S';
opposite = mouseYPos - screenRectCenterY;
}
else
{
mouseRectangleSector[0] = 'N';
opposite = screenRectCenterY - mouseYPos;
}
if (mouseXPos >= screenRectCenterX)
{
mouseRectangleSector[1] = 'E';
adjacent = (screenRectCenterX + tileWidthHalf) - mouseXPos;
}
else{
mouseRectangleSector[1] = 'W';
adjacent = tileWidthHalf - (screenRectCenterX - mouseXPos);
}

double hypothenuse = std::sqrt(std::pow(opposite, 2) + std::pow(adjacent, 2));

//calculate cos and corresponding angle in rad and deg
double cos = adjacent / hypothenuse;
double angleRad = std::acos(cos);
double angleDeg = angleRad * 180 / PI;
//calculate initial rotation angle in rad and deg
double controlAtan = 0.5;
double controlAngleRad = std::atan(controlAtan);
double controlAngleDeg = controlAngleRad * 180 / PI;

//determine final position for y
if (mouseRectangleSector[0] == 'S')
{
if (angleRad > controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}
else
{
if (angleRad < controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}

//determine position for x
double mouseTileXPos;
if ((boost::numeric_cast<int>(mouseTileYPos)) % 2 == 0)
{
mouseTileXPos = (mouseXPos + tileWidthHalf) / tileWidth;
}
else
{
mouseTileXPos = mouseXPos / tileWidth;
}
mouseTileXPos = std::floor(mouseTileXPos);

Point gridXY{(std::size_t)mouseTileXPos, (std::size_t)mouseTileYPos};

return gridXY;
}

int main(int argc, char *args)
{
const double PI = 3.1415926535897932384626433832795;
const int SCREEN_WIDTH = 1600;
const int SCREEN_HEIGHT = 900;

//init SDL Components
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
return 1;
}

SDL_Window *sdlWindow = SDL_CreateWindow("A New Era", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

if (sdlWindow == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
return 1;
}

if (sdlRenderer == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

if (!(IMG_Init(IMG_INIT_PNG)))
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, SDL_ALPHA_OPAQUE);

//tile dimensions
std::size_t tileWidth = 128;
std::size_t tileHeight = 64;
std::size_t tileWidthHalf = tileWidth / 2;
std::size_t tileHeightHalf = tileHeight / 2;
int originX = 0;
int originY = 0;
int xScreenOffset;
int yScreenOffset = 0 - tileHeightHalf;

//add pseudo data points to tile vector
std::vector<Point> mapTiles{};

for (std::size_t y = 0; y < 10; y++)
{
for (std::size_t x = 0; x < 10; x++)
{
Point point{x, y};
mapTiles.push_back(point);
}
}

for (std::vector<Point>::iterator itPoint = mapTiles.begin(); itPoint < mapTiles.end(); itPoint++)
{
if (itPoint->y % 2 == 0)
{
xScreenOffset = 0;
}
else
{
xScreenOffset = tileWidthHalf;
}

//draw 2:1 rombus
std::size_t tileOriginX = itPoint->x * tileWidth;
std::size_t tileOriginY = itPoint->y * tileHeightHalf;
std::size_t x1 = tileOriginX + tileWidthHalf;
std::size_t y1 = tileOriginY + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, tileOriginX + originX + xScreenOffset, tileOriginY + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
std::size_t x = x1;
std::size_t y = y1;
x1 = x - tileWidthHalf;
y1 = y + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = x - tileWidthHalf;
y1 = y - tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = tileOriginX;
y1 = tileOriginY;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
}
SDL_RenderPresent(sdlRenderer);

//game loop
//control variables
SDL_Event event;
bool quit = false;

//originX = originX - tileWidthHalf;
while (!quit)
{
while (SDL_PollEvent(&event) != 0)
{
if (event.type == SDL_QUIT)
{
quit = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
int mouseXPos;
int mouseYPos;
SDL_GetMouseState(&mouseXPos, &mouseYPos);

Point gridCoordinates = mouseToGrid(mouseXPos, mouseYPos, tileWidth, tileHeight, PI, SCREEN_WIDTH, SCREEN_HEIGHT);
std::cout << "x,y : " << gridCoordinates.x << "," << gridCoordinates.y << std::endl;
}
}
}
}

SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 0;
}


As I said, the algorithm works so I don't need help getting it to run. I am looking for help or advice on how to make it more compact (reduce lines of code). Maybe I can get rid of a couple of if statements by doing some more maths. This is really the first time after my graduation I used this kind of maths in programming so there might be some tweaks that can be done.










share|improve this question









New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 3




    Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
    – tinstaafl
    Jan 1 at 17:17












  • I will add a fully functional example tomorrow, thank your for the advice
    – Tremah
    Jan 2 at 0:24










  • the code in my question is now a fully functional minimal example
    – Tremah
    2 days ago














4












4








4







I wrote an algorithm to transform mouse screen coordinates within an isometric map to corresponding coordinates of an underlying 2D-square grid. The algorithm works and I tested it successfully. I wanted to post it here so interested people could maybe check the algorithm and see if I can make any optimizations beyond of what I did already. My goal is to make the algorithm as compact as possible. There maybe are some smart mathematical solutions I didn't think of to save some lines of code or make it faster.



The input data for the rendering of the map is a simple 2D-array like:



0,0,0,0

0,0,0,0

0,0,0,0

...


Here is a screenshot of what the map looks like when rendered. It is not really a map right now but more of an outlining of the tiles I will render. The red coordinates are x and y values of the underlying source grid.



enter image description here



It is rendered with a zig-zag approach with an origin outside of the screen (top left). It is rendered row by row from left to right whereby every uneven row is inset by half a tiles width. This is a common approach to avoid having to fill the source 2D-grid with "zombie-data" if one would render it in a diamond approach.



What the algorithm does is:




  • the screen is logically divided into square rectangles with a width of my tile width and height of my tile height, i.e. 128px by 64px

  • the mouse coordinates are scaled by tile width and tile height and then floored. This determines in which screen rectangle the user clicked

  • then the mouse coordinates are compared against the center coordinates of this rectangle

  • regarding this result, a right angled triangle is calculated to check if the user clicked within a certain area of the rectangle. I am using the cosine of this triangle to compare against my initial rotation angle of 26,565 (atan of 0.5). This is the angle in which the sides of the rendered rhombi are rotated to achieve a 2:1 ratio of width and height (classic isometric projection for video games).

  • regarding on where the user clicked


    • the y value is determined from a lower and upper boundary

    • the x value is determined based on y being even or uneven




To run this code, you will need SDL2-2.0.9 and boost 1.67.0. to run. I am using MS Visual Studio Community 2017 as an IDE.



#include <iostream>
#include <vector>
#include <SDL.h>
#include <SDL_Image.h>
#include <boost/cast.hpp>

struct Point
{
std::size_t x;
std::size_t y;
};

Point mouseToGrid(int pMouseXPos, int pMouseYPos, std::size_t pTileWidth, std::size_t pTileHeight, const double PI, const int SCREEN_WIDTH, const int SCREEN_HEIGHT)
{
double mouseXPos = boost::numeric_cast<double>(pMouseXPos);
double mouseYPos = boost::numeric_cast<double>(pMouseYPos);
double tileWidth = boost::numeric_cast<double>(pTileWidth);
double tileHeight = boost::numeric_cast<double>(pTileHeight);
double tileWidthHalf = tileWidth / 2;
double tileHeightHalf = tileHeight / 2;

double mouseTileYPos = mouseYPos / tileHeight;
mouseTileYPos = std::floor(mouseTileYPos);

int screenRectCenterX = ((std::floor((mouseXPos / tileWidth))) * tileWidth) + tileWidthHalf;
int screenRectCenterY = (mouseTileYPos * tileHeight) + tileHeightHalf;

//determine lower and upper boundary for y
int minY = boost::numeric_cast<int>(2 * mouseTileYPos);
int maxY = boost::numeric_cast<int>((2 * mouseTileYPos) + 1);
if (mouseYPos >= screenRectCenterY)
{
minY = maxY;
maxY++;
}

//calc triangle sides in pixels
char mouseRectangleSector[2]{};
double opposite;
double adjacent;

if (mouseYPos >= screenRectCenterY)
{
mouseRectangleSector[0] = 'S';
opposite = mouseYPos - screenRectCenterY;
}
else
{
mouseRectangleSector[0] = 'N';
opposite = screenRectCenterY - mouseYPos;
}
if (mouseXPos >= screenRectCenterX)
{
mouseRectangleSector[1] = 'E';
adjacent = (screenRectCenterX + tileWidthHalf) - mouseXPos;
}
else{
mouseRectangleSector[1] = 'W';
adjacent = tileWidthHalf - (screenRectCenterX - mouseXPos);
}

double hypothenuse = std::sqrt(std::pow(opposite, 2) + std::pow(adjacent, 2));

//calculate cos and corresponding angle in rad and deg
double cos = adjacent / hypothenuse;
double angleRad = std::acos(cos);
double angleDeg = angleRad * 180 / PI;
//calculate initial rotation angle in rad and deg
double controlAtan = 0.5;
double controlAngleRad = std::atan(controlAtan);
double controlAngleDeg = controlAngleRad * 180 / PI;

//determine final position for y
if (mouseRectangleSector[0] == 'S')
{
if (angleRad > controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}
else
{
if (angleRad < controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}

//determine position for x
double mouseTileXPos;
if ((boost::numeric_cast<int>(mouseTileYPos)) % 2 == 0)
{
mouseTileXPos = (mouseXPos + tileWidthHalf) / tileWidth;
}
else
{
mouseTileXPos = mouseXPos / tileWidth;
}
mouseTileXPos = std::floor(mouseTileXPos);

Point gridXY{(std::size_t)mouseTileXPos, (std::size_t)mouseTileYPos};

return gridXY;
}

int main(int argc, char *args)
{
const double PI = 3.1415926535897932384626433832795;
const int SCREEN_WIDTH = 1600;
const int SCREEN_HEIGHT = 900;

//init SDL Components
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
return 1;
}

SDL_Window *sdlWindow = SDL_CreateWindow("A New Era", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

if (sdlWindow == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
return 1;
}

if (sdlRenderer == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

if (!(IMG_Init(IMG_INIT_PNG)))
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, SDL_ALPHA_OPAQUE);

//tile dimensions
std::size_t tileWidth = 128;
std::size_t tileHeight = 64;
std::size_t tileWidthHalf = tileWidth / 2;
std::size_t tileHeightHalf = tileHeight / 2;
int originX = 0;
int originY = 0;
int xScreenOffset;
int yScreenOffset = 0 - tileHeightHalf;

//add pseudo data points to tile vector
std::vector<Point> mapTiles{};

for (std::size_t y = 0; y < 10; y++)
{
for (std::size_t x = 0; x < 10; x++)
{
Point point{x, y};
mapTiles.push_back(point);
}
}

for (std::vector<Point>::iterator itPoint = mapTiles.begin(); itPoint < mapTiles.end(); itPoint++)
{
if (itPoint->y % 2 == 0)
{
xScreenOffset = 0;
}
else
{
xScreenOffset = tileWidthHalf;
}

//draw 2:1 rombus
std::size_t tileOriginX = itPoint->x * tileWidth;
std::size_t tileOriginY = itPoint->y * tileHeightHalf;
std::size_t x1 = tileOriginX + tileWidthHalf;
std::size_t y1 = tileOriginY + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, tileOriginX + originX + xScreenOffset, tileOriginY + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
std::size_t x = x1;
std::size_t y = y1;
x1 = x - tileWidthHalf;
y1 = y + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = x - tileWidthHalf;
y1 = y - tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = tileOriginX;
y1 = tileOriginY;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
}
SDL_RenderPresent(sdlRenderer);

//game loop
//control variables
SDL_Event event;
bool quit = false;

//originX = originX - tileWidthHalf;
while (!quit)
{
while (SDL_PollEvent(&event) != 0)
{
if (event.type == SDL_QUIT)
{
quit = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
int mouseXPos;
int mouseYPos;
SDL_GetMouseState(&mouseXPos, &mouseYPos);

Point gridCoordinates = mouseToGrid(mouseXPos, mouseYPos, tileWidth, tileHeight, PI, SCREEN_WIDTH, SCREEN_HEIGHT);
std::cout << "x,y : " << gridCoordinates.x << "," << gridCoordinates.y << std::endl;
}
}
}
}

SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 0;
}


As I said, the algorithm works so I don't need help getting it to run. I am looking for help or advice on how to make it more compact (reduce lines of code). Maybe I can get rid of a couple of if statements by doing some more maths. This is really the first time after my graduation I used this kind of maths in programming so there might be some tweaks that can be done.










share|improve this question









New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I wrote an algorithm to transform mouse screen coordinates within an isometric map to corresponding coordinates of an underlying 2D-square grid. The algorithm works and I tested it successfully. I wanted to post it here so interested people could maybe check the algorithm and see if I can make any optimizations beyond of what I did already. My goal is to make the algorithm as compact as possible. There maybe are some smart mathematical solutions I didn't think of to save some lines of code or make it faster.



The input data for the rendering of the map is a simple 2D-array like:



0,0,0,0

0,0,0,0

0,0,0,0

...


Here is a screenshot of what the map looks like when rendered. It is not really a map right now but more of an outlining of the tiles I will render. The red coordinates are x and y values of the underlying source grid.



enter image description here



It is rendered with a zig-zag approach with an origin outside of the screen (top left). It is rendered row by row from left to right whereby every uneven row is inset by half a tiles width. This is a common approach to avoid having to fill the source 2D-grid with "zombie-data" if one would render it in a diamond approach.



What the algorithm does is:




  • the screen is logically divided into square rectangles with a width of my tile width and height of my tile height, i.e. 128px by 64px

  • the mouse coordinates are scaled by tile width and tile height and then floored. This determines in which screen rectangle the user clicked

  • then the mouse coordinates are compared against the center coordinates of this rectangle

  • regarding this result, a right angled triangle is calculated to check if the user clicked within a certain area of the rectangle. I am using the cosine of this triangle to compare against my initial rotation angle of 26,565 (atan of 0.5). This is the angle in which the sides of the rendered rhombi are rotated to achieve a 2:1 ratio of width and height (classic isometric projection for video games).

  • regarding on where the user clicked


    • the y value is determined from a lower and upper boundary

    • the x value is determined based on y being even or uneven




To run this code, you will need SDL2-2.0.9 and boost 1.67.0. to run. I am using MS Visual Studio Community 2017 as an IDE.



#include <iostream>
#include <vector>
#include <SDL.h>
#include <SDL_Image.h>
#include <boost/cast.hpp>

struct Point
{
std::size_t x;
std::size_t y;
};

Point mouseToGrid(int pMouseXPos, int pMouseYPos, std::size_t pTileWidth, std::size_t pTileHeight, const double PI, const int SCREEN_WIDTH, const int SCREEN_HEIGHT)
{
double mouseXPos = boost::numeric_cast<double>(pMouseXPos);
double mouseYPos = boost::numeric_cast<double>(pMouseYPos);
double tileWidth = boost::numeric_cast<double>(pTileWidth);
double tileHeight = boost::numeric_cast<double>(pTileHeight);
double tileWidthHalf = tileWidth / 2;
double tileHeightHalf = tileHeight / 2;

double mouseTileYPos = mouseYPos / tileHeight;
mouseTileYPos = std::floor(mouseTileYPos);

int screenRectCenterX = ((std::floor((mouseXPos / tileWidth))) * tileWidth) + tileWidthHalf;
int screenRectCenterY = (mouseTileYPos * tileHeight) + tileHeightHalf;

//determine lower and upper boundary for y
int minY = boost::numeric_cast<int>(2 * mouseTileYPos);
int maxY = boost::numeric_cast<int>((2 * mouseTileYPos) + 1);
if (mouseYPos >= screenRectCenterY)
{
minY = maxY;
maxY++;
}

//calc triangle sides in pixels
char mouseRectangleSector[2]{};
double opposite;
double adjacent;

if (mouseYPos >= screenRectCenterY)
{
mouseRectangleSector[0] = 'S';
opposite = mouseYPos - screenRectCenterY;
}
else
{
mouseRectangleSector[0] = 'N';
opposite = screenRectCenterY - mouseYPos;
}
if (mouseXPos >= screenRectCenterX)
{
mouseRectangleSector[1] = 'E';
adjacent = (screenRectCenterX + tileWidthHalf) - mouseXPos;
}
else{
mouseRectangleSector[1] = 'W';
adjacent = tileWidthHalf - (screenRectCenterX - mouseXPos);
}

double hypothenuse = std::sqrt(std::pow(opposite, 2) + std::pow(adjacent, 2));

//calculate cos and corresponding angle in rad and deg
double cos = adjacent / hypothenuse;
double angleRad = std::acos(cos);
double angleDeg = angleRad * 180 / PI;
//calculate initial rotation angle in rad and deg
double controlAtan = 0.5;
double controlAngleRad = std::atan(controlAtan);
double controlAngleDeg = controlAngleRad * 180 / PI;

//determine final position for y
if (mouseRectangleSector[0] == 'S')
{
if (angleRad > controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}
else
{
if (angleRad < controlAngleRad)
{
mouseTileYPos = maxY;
}
else
{
mouseTileYPos = minY;
}
}

//determine position for x
double mouseTileXPos;
if ((boost::numeric_cast<int>(mouseTileYPos)) % 2 == 0)
{
mouseTileXPos = (mouseXPos + tileWidthHalf) / tileWidth;
}
else
{
mouseTileXPos = mouseXPos / tileWidth;
}
mouseTileXPos = std::floor(mouseTileXPos);

Point gridXY{(std::size_t)mouseTileXPos, (std::size_t)mouseTileYPos};

return gridXY;
}

int main(int argc, char *args)
{
const double PI = 3.1415926535897932384626433832795;
const int SCREEN_WIDTH = 1600;
const int SCREEN_HEIGHT = 900;

//init SDL Components
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
return 1;
}

SDL_Window *sdlWindow = SDL_CreateWindow("A New Era", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

if (sdlWindow == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
return 1;
}

if (sdlRenderer == nullptr)
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

if (!(IMG_Init(IMG_INIT_PNG)))
{
SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 1;
}

SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 255, SDL_ALPHA_OPAQUE);

//tile dimensions
std::size_t tileWidth = 128;
std::size_t tileHeight = 64;
std::size_t tileWidthHalf = tileWidth / 2;
std::size_t tileHeightHalf = tileHeight / 2;
int originX = 0;
int originY = 0;
int xScreenOffset;
int yScreenOffset = 0 - tileHeightHalf;

//add pseudo data points to tile vector
std::vector<Point> mapTiles{};

for (std::size_t y = 0; y < 10; y++)
{
for (std::size_t x = 0; x < 10; x++)
{
Point point{x, y};
mapTiles.push_back(point);
}
}

for (std::vector<Point>::iterator itPoint = mapTiles.begin(); itPoint < mapTiles.end(); itPoint++)
{
if (itPoint->y % 2 == 0)
{
xScreenOffset = 0;
}
else
{
xScreenOffset = tileWidthHalf;
}

//draw 2:1 rombus
std::size_t tileOriginX = itPoint->x * tileWidth;
std::size_t tileOriginY = itPoint->y * tileHeightHalf;
std::size_t x1 = tileOriginX + tileWidthHalf;
std::size_t y1 = tileOriginY + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, tileOriginX + originX + xScreenOffset, tileOriginY + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
std::size_t x = x1;
std::size_t y = y1;
x1 = x - tileWidthHalf;
y1 = y + tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = x - tileWidthHalf;
y1 = y - tileHeightHalf;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
x = x1;
y = y1;
x1 = tileOriginX;
y1 = tileOriginY;
SDL_RenderDrawLine(sdlRenderer, x + originX + xScreenOffset, y + originY + yScreenOffset, x1 + originX + xScreenOffset, y1 + originY + yScreenOffset);
}
SDL_RenderPresent(sdlRenderer);

//game loop
//control variables
SDL_Event event;
bool quit = false;

//originX = originX - tileWidthHalf;
while (!quit)
{
while (SDL_PollEvent(&event) != 0)
{
if (event.type == SDL_QUIT)
{
quit = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
int mouseXPos;
int mouseYPos;
SDL_GetMouseState(&mouseXPos, &mouseYPos);

Point gridCoordinates = mouseToGrid(mouseXPos, mouseYPos, tileWidth, tileHeight, PI, SCREEN_WIDTH, SCREEN_HEIGHT);
std::cout << "x,y : " << gridCoordinates.x << "," << gridCoordinates.y << std::endl;
}
}
}
}

SDL_DestroyWindow(sdlWindow);
SDL_DestroyRenderer(sdlRenderer);
SDL_Quit();
return 0;
}


As I said, the algorithm works so I don't need help getting it to run. I am looking for help or advice on how to make it more compact (reduce lines of code). Maybe I can get rid of a couple of if statements by doing some more maths. This is really the first time after my graduation I used this kind of maths in programming so there might be some tweaks that can be done.







c++ game coordinate-system






share|improve this question









New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Jan 2 at 2:16





















New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Jan 1 at 17:05









Tremah

212




212




New contributor




Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Tremah is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 3




    Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
    – tinstaafl
    Jan 1 at 17:17












  • I will add a fully functional example tomorrow, thank your for the advice
    – Tremah
    Jan 2 at 0:24










  • the code in my question is now a fully functional minimal example
    – Tremah
    2 days ago














  • 3




    Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
    – tinstaafl
    Jan 1 at 17:17












  • I will add a fully functional example tomorrow, thank your for the advice
    – Tremah
    Jan 2 at 0:24










  • the code in my question is now a fully functional minimal example
    – Tremah
    2 days ago








3




3




Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
– tinstaafl
Jan 1 at 17:17






Code stubs aren't appropriate for this site. Flesh it out to make it a complete code with the minimal amount required to compile and run it.
– tinstaafl
Jan 1 at 17:17














I will add a fully functional example tomorrow, thank your for the advice
– Tremah
Jan 2 at 0:24




I will add a fully functional example tomorrow, thank your for the advice
– Tremah
Jan 2 at 0:24












the code in my question is now a fully functional minimal example
– Tremah
2 days ago




the code in my question is now a fully functional minimal example
– Tremah
2 days ago










1 Answer
1






active

oldest

votes


















0














If it is immaterial whether minY or maxY is used in case of angleRad == controlAngleRad, you can avoid duplication in the final position for y-handling:



//determine final position for y
mouseTileYPos = (mouseRectangleSector[0] == 'S')
== (angleRad > controlAngleRad) ? maxY : minY;





share|improve this answer





















  • As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
    – greybeard
    Jan 1 at 19:13











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






Tremah is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210695%2fmouse-coordinates-to-grid-coordinates-within-an-isometric-map%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














If it is immaterial whether minY or maxY is used in case of angleRad == controlAngleRad, you can avoid duplication in the final position for y-handling:



//determine final position for y
mouseTileYPos = (mouseRectangleSector[0] == 'S')
== (angleRad > controlAngleRad) ? maxY : minY;





share|improve this answer





















  • As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
    – greybeard
    Jan 1 at 19:13
















0














If it is immaterial whether minY or maxY is used in case of angleRad == controlAngleRad, you can avoid duplication in the final position for y-handling:



//determine final position for y
mouseTileYPos = (mouseRectangleSector[0] == 'S')
== (angleRad > controlAngleRad) ? maxY : minY;





share|improve this answer





















  • As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
    – greybeard
    Jan 1 at 19:13














0












0








0






If it is immaterial whether minY or maxY is used in case of angleRad == controlAngleRad, you can avoid duplication in the final position for y-handling:



//determine final position for y
mouseTileYPos = (mouseRectangleSector[0] == 'S')
== (angleRad > controlAngleRad) ? maxY : minY;





share|improve this answer












If it is immaterial whether minY or maxY is used in case of angleRad == controlAngleRad, you can avoid duplication in the final position for y-handling:



//determine final position for y
mouseTileYPos = (mouseRectangleSector[0] == 'S')
== (angleRad > controlAngleRad) ? maxY : minY;






share|improve this answer












share|improve this answer



share|improve this answer










answered Jan 1 at 19:12









greybeard

1,3491621




1,3491621












  • As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
    – greybeard
    Jan 1 at 19:13


















  • As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
    – greybeard
    Jan 1 at 19:13
















As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
– greybeard
Jan 1 at 19:13




As for number of lines, I prefer block delimiters in-line with control structures, and more often than not use them when mandatory, only. IDEs and tools like indent (the flags *do me*.) are good at bulk-changing such conventions to see whether one prefers one convention over the other.
– greybeard
Jan 1 at 19:13










Tremah is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















Tremah is a new contributor. Be nice, and check out our Code of Conduct.













Tremah is a new contributor. Be nice, and check out our Code of Conduct.












Tremah is a new contributor. Be nice, and check out our Code of Conduct.
















Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210695%2fmouse-coordinates-to-grid-coordinates-within-an-isometric-map%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Список кардиналов, возведённых папой римским Каликстом III

Deduzione

Mysql.sock missing - “Can't connect to local MySQL server through socket”