[Freeciv-Dev] (PR#1180) [PATCH] cleanup to canvas_pos_to_map_pos
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
[glip - Tue Nov 19 20:56:43 2002]:
> So, skipping N_T_ stuff and cancelling the common factors, the
> transformation is
>
> x_map = [ x / W + y / H]
> y_map = [ y / H - x / W]
Here's a new patch. It still has what Ross calls the "DIVIDE ugliness",
but the operations are made atomic and described as a whole. It refers
the your diagram by its URL right here in RT - alternately the diagram
could be put into CVS (in /doc) or onto the main freeciv web site.
jason
Index: client/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.11
diff -u -r1.11 citydlg_common.c
--- client/citydlg_common.c 2002/11/14 09:14:50 1.11
+++ client/citydlg_common.c 2002/11/20 01:31:24
@@ -55,35 +55,30 @@
**************************************************************************/
void canvas_pos_to_city_pos(int canvas_x, int canvas_y, int *map_x, int *map_y)
{
+ int orig_canvas_x = canvas_x, orig_canvas_y = canvas_y;
+
if (is_isometric) {
- *map_x = -2;
- *map_y = 2;
+ const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
- /* first find an equivalent position on the left side of the screen. */
- *map_x += canvas_x / NORMAL_TILE_WIDTH;
- *map_y -= canvas_x / NORMAL_TILE_WIDTH;
- canvas_x %= NORMAL_TILE_WIDTH;
+ /* Shift the tile right so the top corner of tile (-2,2) is at
+ canvas position (0,0). */
+ canvas_y += NORMAL_TILE_HEIGHT / 2;
- /* Then move op to the top corner. */
- *map_x += canvas_y / NORMAL_TILE_HEIGHT;
- *map_y += canvas_y / NORMAL_TILE_HEIGHT;
- canvas_y %= NORMAL_TILE_HEIGHT;
+ /* Perform a pi/4 rotation, with scaling. See canvas_pos_to_map_pos
+ for a full explanation. */
+ *map_x = DIVIDE(canvas_x * H + canvas_y * W, W * H);
+ *map_y = DIVIDE(canvas_y * W - canvas_x * H, W * H);
- assert(NORMAL_TILE_WIDTH == 2 * NORMAL_TILE_HEIGHT);
- canvas_y *= 2; /* now we have a square. */
- if (canvas_x + canvas_y > NORMAL_TILE_WIDTH / 2)
- (*map_x)++;
- if (canvas_x + canvas_y > 3 * NORMAL_TILE_WIDTH / 2)
- (*map_x)++;
- if (canvas_x - canvas_y > NORMAL_TILE_WIDTH / 2)
- (*map_y)--;
- if (canvas_y - canvas_x > NORMAL_TILE_WIDTH / 2)
- (*map_y)++;
+ /* Add on the offset of the top-left corner to get the final
+ coordinates (like in canvas_pos_to_map_pos). */
+ *map_x -= 2;
+ *map_y += 2;
} else {
*map_x = canvas_x / NORMAL_TILE_WIDTH;
*map_y = canvas_y / NORMAL_TILE_HEIGHT;
}
- freelog(LOG_DEBUG, "canvas_pos_to_city_pos(pos=(%d,%d))=(%d,%d)", canvas_x,
canvas_y, *map_x, *map_y);
+ freelog(LOG_DEBUG, "canvas_pos_to_city_pos(pos=(%d,%d))=(%d,%d)",
+ orig_canvas_x, orig_canvas_y, *map_x, *map_y);
}
/**************************************************************************
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.15
diff -u -r1.15 mapview_common.c
--- client/mapview_common.c 2002/11/19 20:13:38 1.15
+++ client/mapview_common.c 2002/11/20 01:31:24
@@ -187,34 +187,42 @@
int map_view_topleft_map_y)
{
if (is_isometric) {
- *map_x = map_view_topleft_map_x;
- *map_y = map_view_topleft_map_y;
+ /* The basic operation here is a simple pi/4 rotation; however, we
+ * have to first scale because the tiles have different width and
+ * height. Mathematically, this looks like
+ * | 1/W 1/H | |x| |x`|
+ * | | | | -> | |
+ * |-1/W 1/H | |y| |y`|
+ *
+ * Where W is the tile width and H the height.
+ *
+ * In simple terms, this is
+ * map_x = [ x / W + y / H ]
+ * map_y = [ - x / W + y / H ]
+ * where [q] stands for integer part of q.
+ *
+ * Here the division is proper mathematical floating point division.
+ *
+ * A picture demonstrating this can be seen at
+ * http://rt.freeciv.org/Ticket/Attachment/16782/9982/grid1.png.
+ *
+ * The calculation is complicated somewhat because of two things: we
+ * only use integer math, and C integer division rounds toward zero
+ * instead of rounding down.
+ *
+ * For another example of this math, see canvas_pos_to_city_pos().
+ */
+ const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
- /* first find an equivalent position on the left side of the screen. */
- *map_x += canvas_x / NORMAL_TILE_WIDTH;
- *map_y -= canvas_x / NORMAL_TILE_WIDTH;
- canvas_x %= NORMAL_TILE_WIDTH;
-
- /* Then move op to the top corner. */
- *map_x += canvas_y / NORMAL_TILE_HEIGHT;
- *map_y += canvas_y / NORMAL_TILE_HEIGHT;
- canvas_y %= NORMAL_TILE_HEIGHT;
-
- /* We are inside a rectangle, with 2 half tiles starting in the
- corner, and two tiles further out. Draw a grid to see how this
- works :). */
- assert(NORMAL_TILE_WIDTH == 2 * NORMAL_TILE_HEIGHT);
- canvas_y *= 2; /* now we have a square. */
- if (canvas_x > canvas_y) {
- *map_y -= 1;
- }
- if (canvas_x + canvas_y > NORMAL_TILE_WIDTH) {
- *map_x += 1;
- }
+ *map_x = DIVIDE(canvas_x * H + canvas_y * W, W * H);
+ *map_y = DIVIDE(canvas_y * W - canvas_x * H, W * H);
} else { /* is_isometric */
- *map_x = map_view_topleft_map_x + canvas_x / NORMAL_TILE_WIDTH;
- *map_y = map_view_topleft_map_y + canvas_y / NORMAL_TILE_HEIGHT;
+ *map_x = canvas_x / NORMAL_TILE_WIDTH;
+ *map_y = canvas_y / NORMAL_TILE_HEIGHT;
}
+
+ *map_x += map_view_topleft_map_x;
+ *map_y += map_view_topleft_map_y;
/*
* If we are outside the map find the nearest tile, with distance as
Index: common/shared.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/shared.h,v
retrieving revision 1.105
diff -u -r1.105 shared.h
--- common/shared.h 2002/11/13 19:44:25 1.105
+++ common/shared.h 2002/11/20 01:31:24
@@ -65,6 +65,13 @@
#define BOOL_VAL(x) ((x)!=0)
+/*
+ * DIVIDE() divides and rounds down, rather than just divides and
+ * rounds toward 0.
+ */
+#define DIVIDE(n, d) \
+ ((n) % (d) < 0 ? (n) / (d) - 1 : (n) / (d))
+
/* Deletes bit no in val,
moves all bits larger than no one down,
and inserts a zero at the top. */
|
|