diff options
author | rubidium <rubidium@openttd.org> | 2010-12-13 15:13:05 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2010-12-13 15:13:05 +0000 |
commit | b20e77be921acc32b5887f9f35ecae8573c588af (patch) | |
tree | ab5efe19852fb742a511f9b386f5547875dc5996 | |
parent | 652e2626010c3cc1a92875ccbaeed61233b1d6fc (diff) | |
download | openttd-b20e77be921acc32b5887f9f35ecae8573c588af.tar.xz |
(svn r21499) -Add: diagonal tile iterator. Based on patch by fonsinchen
-rw-r--r-- | src/tilearea.cpp | 61 | ||||
-rw-r--r-- | src/tilearea_type.h | 24 |
2 files changed, 84 insertions, 1 deletions
diff --git a/src/tilearea.cpp b/src/tilearea.cpp index 7a2d76d70..74f701315 100644 --- a/src/tilearea.cpp +++ b/src/tilearea.cpp @@ -104,3 +104,64 @@ void TileArea::ClampToMap() this->h = min(this->h, MapSizeY() - TileY(this->tile)); } +DiagonalTileIterator::DiagonalTileIterator(TileIndex corner1, TileIndex corner2) : TileIterator(corner2), base_x(TileX(corner2)), base_y(TileY(corner2)), a_cur(0), b_cur(0) +{ + assert(corner1 < MapSize()); + assert(corner2 < MapSize()); + + int dist_x = TileX(corner1) - TileX(corner2); + int dist_y = TileY(corner1) - TileY(corner2); + this->a_max = dist_x + dist_y; + this->b_max = dist_y - dist_x; + + /* Unfortunately we can't find a new base and make all a and b positive because + * the new base might be a "flattened" corner where there actually is no single + * tile. If we try anyway the result is either inaccurate ("one off" half of the + * time) or the code gets much more complex; + * + * We also need to increment here to have equality as marker for the end of a row or + * column. Like that it's shorter than having another if/else in operator++ + */ + if (this->a_max > 0) { + this->a_max++; + } else { + this->a_max--; + } + + if (this->b_max > 0) { + this->b_max++; + } else { + this->b_max--; + } +} + +TileIterator &DiagonalTileIterator::operator++() +{ + assert(this->tile != INVALID_TILE); + + do { + /* Iterate using the rotated coordinates. */ + if (this->a_max > 0) { + ++this->a_cur; + } else { + --this->a_cur; + } + if (this->a_cur == this->a_max) { + this->a_cur = 0; + if (this->b_max > 0) { + ++this->b_cur; + } else { + --this->b_cur; + } + } + + /* And convert the coordinates back once we've gone to the next tile. */ + uint x = this->base_x + (this->a_cur - this->b_cur) / 2; + uint y = this->base_y + (this->b_cur + this->a_cur) / 2; + /* Prevent wrapping around the map's borders. */ + this->tile = x >= MapSizeX() || y >= MapSizeY() ? INVALID_TILE : TileXY(x, y); + } while (this->tile > MapSize() && this->b_max != this->b_cur); + + if (this->b_max == this->b_cur) this->tile = INVALID_TILE; + return *this; +} diff --git a/src/tilearea_type.h b/src/tilearea_type.h index 44a2ba3c2..23813eeb8 100644 --- a/src/tilearea_type.h +++ b/src/tilearea_type.h @@ -73,11 +73,12 @@ protected: { } +public: /** Some compilers really like this. */ virtual ~TileIterator() { } -public: + /** * Get the tile we are currently at. * @return The tile we are at, or INVALID_TILE when we're done. @@ -128,6 +129,27 @@ public: } }; +/** Iterator to iterate over a diagonal area of the map. */ +class DiagonalTileIterator : public TileIterator { +private: + uint base_x, base_y; ///< The base tile x and y coordinates from where the iterating happens. + int a_cur, b_cur; ///< The current (rotated) x and y coordinates of the iteration. + int a_max, b_max; ///< The (rotated) x and y coordinates of the end of the iteration. + +public: + /** + * Construct the iterator. + * @param begin Tile from where to begin iterating. + * @param end Tile where to end the iterating. + */ + DiagonalTileIterator(TileIndex begin, TileIndex end); + + /** + * Move ourselves to the next tile in the rectange on the map. + */ + TileIterator& operator ++(); +}; + /** * A loop which iterates over the tiles of a TileArea. * @param var The name of the variable which contains the current tile. |