Freeciv21
Develop your civilization from humble roots to a global empire
view_map_geometry.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 1996-2020 Freeciv and Freeciv21 contributors
3  * SPDX-FileCopyrightText: 2022-2023 Louis Moureaux <m_louis30@yahoo.com>
4  *
5  * SPDX-License-Identifier: GPLv3-or-later
6  */
7 
8 /*
9  * This file contains tileset geometry functions to manipulate the GUI for
10  * the the main map view.
11  */
12 
14 
15 #include "game.h"
16 #include "map.h"
17 #include "tileset/tilespec.h"
18 
19 namespace freeciv {
20 
149  const QRect &rect)
150 {
151  const auto normalized = rect.normalized();
152  if (!normalized.isValid()) {
153  m_index = 0;
154  m_count = 0; // Don't iterate
155  return;
156  }
157 
159 
160  m_r1 = m_isometric ? 2 : 1;
161  m_r2 = m_r1 * 2; // double the ratio
162  m_w = tileset_tile_width(t);
164 
165  // Don't divide by r2 yet, to avoid integer rounding errors.
166  m_x0 = DIVIDE(normalized.left() * m_r2, m_w) - m_r1 / 2;
167  m_y0 = DIVIDE(normalized.top() * m_r2, m_h) - m_r1 / 2;
168  m_x1 = DIVIDE(normalized.right() * m_r2 + m_w - 1, m_w) + m_r1;
169  m_y1 = DIVIDE(normalized.bottom() * m_r2 + m_h - 1, m_h) + m_r1;
170 
171  // Start counting
172  m_index = 0;
173  m_count = (m_x1 - m_x0) * (m_y1 - m_y0);
174 
175  log_debug("Iterating over %d-%d x %d-%d rectangle.", m_x1, m_x0, m_y1,
176  m_y0);
177 }
178 
184 {
185  if (m_index >= m_count) {
186  return false;
187  }
188 
189  m_tile = nullptr;
190  m_has_corner = false;
191  m_has_edge = false;
192  m_has_tile = false;
193 
194  m_xi = m_x0 + (m_index % (m_x1 - m_x0));
195  m_yi = m_y0 + (m_index / (m_x1 - m_x0));
196 
197  const auto si = m_xi + m_yi;
198  const auto di = m_yi - m_xi;
199 
200  if (m_isometric) {
201  if ((m_xi + m_yi) % 2 != 0) {
202  m_index++;
203  return next();
204  }
205 
206  if (m_xi % 2 == 0 && m_yi % 2 == 0) {
207  if ((m_xi + m_yi) % 4 == 0) {
208  // Tile
209  m_tile = map_pos_to_tile(&(wld.map), si / 4 - 1, di / 4);
210  m_has_tile = (m_tile != nullptr);
211  } else {
212  // Corner
213  m_has_corner = true;
214  m_corner.tile[0] =
215  map_pos_to_tile(&(wld.map), (si - 6) / 4, (di - 2) / 4);
216  m_corner.tile[1] =
217  map_pos_to_tile(&(wld.map), (si - 2) / 4, (di - 2) / 4);
218  m_corner.tile[2] =
219  map_pos_to_tile(&(wld.map), (si - 2) / 4, (di + 2) / 4);
220  m_corner.tile[3] =
221  map_pos_to_tile(&(wld.map), (si - 6) / 4, (di + 2) / 4);
222  if (tileset_hex_width(tileset) > 0) {
223  m_has_edge = true;
224  m_edge.type = EDGE_UD;
225  m_edge.tile[0] = m_corner.tile[0];
226  m_edge.tile[1] = m_corner.tile[2];
227  } else if (tileset_hex_height(tileset) > 0) {
228  m_has_edge = true;
229  m_edge.type = EDGE_LR;
230  m_edge.tile[0] = m_corner.tile[1];
231  m_edge.tile[1] = m_corner.tile[3];
232  }
233  }
234  } else {
235  // Edge.
236  m_has_edge = true;
237  if (si % 4 == 0) {
238  m_edge.type = EDGE_NS;
239  m_edge.tile[0] = map_pos_to_tile(&(wld.map), (si - 4) / 4,
240  (di - 2) / 4); // N
241  m_edge.tile[1] = map_pos_to_tile(&(wld.map), (si - 4) / 4,
242  (di + 2) / 4); // S
243  } else {
244  m_edge.type = EDGE_WE;
245  m_edge.tile[0] = map_pos_to_tile(&(wld.map), (si - 6) / 4,
246  di / 4); // W
247  m_edge.tile[1] = map_pos_to_tile(&(wld.map), (si - 2) / 4,
248  di / 4); // E
249  }
250  }
251  } else {
252  if (si % 2 == 0) {
253  if (m_xi % 2 == 0) {
254  // Corner.
255  m_has_corner = true;
256  m_corner.tile[0] = map_pos_to_tile(&(wld.map), m_xi / 2 - 1,
257  m_yi / 2 - 1); // NW
258  m_corner.tile[1] = map_pos_to_tile(&(wld.map), m_xi / 2,
259  m_yi / 2 - 1); // NE
260  m_corner.tile[2] = map_pos_to_tile(&(wld.map), m_xi / 2,
261  m_yi / 2); // SE
262  m_corner.tile[3] = map_pos_to_tile(&(wld.map), m_xi / 2 - 1,
263  m_yi / 2); // SW
264  } else {
265  // Tile.
266  m_tile = map_pos_to_tile(&(wld.map), (m_xi - 1) / 2, (m_yi - 1) / 2);
267  m_has_tile = (m_tile != nullptr);
268  }
269  } else {
270  // Edge.
271  m_has_edge = true;
272  if (m_yi % 2 == 0) {
273  m_edge.type = EDGE_NS;
274  m_edge.tile[0] = map_pos_to_tile(&(wld.map), (m_xi - 1) / 2,
275  m_yi / 2 - 1); // N
276  m_edge.tile[1] = map_pos_to_tile(&(wld.map), (m_xi - 1) / 2,
277  m_yi / 2); // S
278  } else {
279  m_edge.type = EDGE_WE;
280  m_edge.tile[0] = map_pos_to_tile(&(wld.map), m_xi / 2 - 1,
281  (m_yi - 1) / 2); // W
282  m_edge.tile[1] = map_pos_to_tile(&(wld.map), m_xi / 2,
283  (m_yi - 1) / 2); // E
284  }
285  }
286  }
287 
288  m_index++;
289  return true;
290 }
291 
292 } // namespace freeciv
gui_rect_iterator(const struct tileset *t, const QRect &rect)
Constructor.
bool next()
Iterates to the next item.
struct world wld
Definition: game.cpp:48
@ EDGE_WE
Definition: layer.h:33
@ EDGE_UD
Definition: layer.h:34
@ EDGE_LR
Definition: layer.h:35
@ EDGE_NS
Definition: layer.h:32
#define log_debug(message,...)
Definition: log.h:65
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Return the tile for the given cartesian (map) position.
Definition: map.cpp:391
Definition: path.cpp:10
#define DIVIDE(n, d)
Definition: shared.h:71
const struct tile * tile[NUM_CORNER_TILES]
Definition: layer.h:49
const struct tile * tile[NUM_EDGE_TILES]
Definition: layer.h:42
edge_type type
Definition: layer.h:40
struct civ_map map
Definition: world_object.h:21
int tileset_hex_width(const struct tileset *t)
Return the hex_width of the current tileset.
Definition: tilespec.cpp:345
bool tileset_is_isometric(const struct tileset *t)
Return whether the current tileset is isometric.
Definition: tilespec.cpp:336
int tileset_tile_height(const struct tileset *t)
Return the tile height of the current tileset.
Definition: tilespec.cpp:383
int tileset_hex_height(const struct tileset *t)
Return the hex_height of the current tileset.
Definition: tilespec.cpp:351
int tileset_tile_width(const struct tileset *t)
Return the tile width of the current tileset.
Definition: tilespec.cpp:371