1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file tilearea_type.h Type for storing the 'area' of something uses on the map. */
9 
10 #ifndef TILEAREA_TYPE_H
11 #define TILEAREA_TYPE_H
12 
13 #include "map_func.h"
14 
15 class OrthogonalTileIterator;
16 
17 /** Represents the covered area of e.g. a rail station */
18 struct OrthogonalTileArea {
19 	TileIndex tile; ///< The base tile of the area
20 	uint16 w;       ///< The width of the area
21 	uint16 h;       ///< The height of the area
22 
23 	/**
24 	 * Construct this tile area with some set values
25 	 * @param tile the base tile
26 	 * @param w the width
27 	 * @param h the height
28 	 */
tileOrthogonalTileArea29 	OrthogonalTileArea(TileIndex tile = INVALID_TILE, uint8 w = 0, uint8 h = 0) : tile(tile), w(w), h(h)
30 	{
31 	}
32 
33 	OrthogonalTileArea(TileIndex start, TileIndex end);
34 
35 	void Add(TileIndex to_add);
36 
37 	/**
38 	 * Clears the 'tile area', i.e. make the tile invalid.
39 	 */
ClearOrthogonalTileArea40 	void Clear()
41 	{
42 		this->tile = INVALID_TILE;
43 		this->w    = 0;
44 		this->h    = 0;
45 	}
46 
47 	bool Intersects(const OrthogonalTileArea &ta) const;
48 
49 	bool Contains(TileIndex tile) const;
50 
51 	OrthogonalTileArea &Expand(int rad);
52 
53 	void ClampToMap();
54 
55 	/**
56 	 * Get the center tile.
57 	 * @return The tile at the center, or just north of it.
58 	 */
GetCenterTileOrthogonalTileArea59 	TileIndex GetCenterTile() const
60 	{
61 		return TILE_ADDXY(this->tile, this->w / 2, this->h / 2);
62 	}
63 
64 	OrthogonalTileIterator begin() const;
65 
66 	OrthogonalTileIterator end() const;
67 };
68 
69 /** Represents a diagonal tile area. */
70 struct DiagonalTileArea {
71 
72 	TileIndex tile; ///< Base tile of the area
73 	int16 a;        ///< Extent in diagonal "x" direction (may be negative to signify the area stretches to the left)
74 	int16 b;        ///< Extent in diagonal "y" direction (may be negative to signify the area stretches upwards)
75 
76 	/**
77 	 * Construct this tile area with some set values.
78 	 * @param tile The base tile.
79 	 * @param a The "x" extent.
80 	 * @param b The "y" estent.
81 	 */
tileDiagonalTileArea82 	DiagonalTileArea(TileIndex tile = INVALID_TILE, int8 a = 0, int8 b = 0) : tile(tile), a(a), b(b)
83 	{
84 	}
85 
86 	DiagonalTileArea(TileIndex start, TileIndex end);
87 
88 	/**
89 	 * Clears the TileArea by making the tile invalid and setting a and b to 0.
90 	 */
ClearDiagonalTileArea91 	void Clear()
92 	{
93 		this->tile = INVALID_TILE;
94 		this->a    = 0;
95 		this->b    = 0;
96 	}
97 
98 	bool Contains(TileIndex tile) const;
99 };
100 
101 /** Shorthand for the much more common orthogonal tile area. */
102 typedef OrthogonalTileArea TileArea;
103 
104 /** Base class for tile iterators. */
105 class TileIterator {
106 protected:
107 	TileIndex tile; ///< The current tile we are at.
108 
109 	/**
110 	 * Initialise the iterator starting at this tile.
111 	 * @param tile The tile we start iterating from.
112 	 */
tile(tile)113 	TileIterator(TileIndex tile = INVALID_TILE) : tile(tile)
114 	{
115 	}
116 
117 public:
118 	/** Some compilers really like this. */
~TileIterator()119 	virtual ~TileIterator()
120 	{
121 	}
122 
123 	/**
124 	 * Get the tile we are currently at.
125 	 * @return The tile we are at, or INVALID_TILE when we're done.
126 	 */
TileIndex()127 	inline operator TileIndex () const
128 	{
129 		return this->tile;
130 	}
131 
132 	/**
133 	 * Get the tile we are currently at.
134 	 * @return The tile we are at, or INVALID_TILE when we're done.
135 	 */
136 	inline TileIndex operator *() const
137 	{
138 		return this->tile;
139 	}
140 
141 	/**
142 	 * Move ourselves to the next tile in the rectangle on the map.
143 	 */
144 	virtual TileIterator& operator ++() = 0;
145 
146 	/**
147 	 * Allocate a new iterator that is a copy of this one.
148 	 */
149 	virtual TileIterator *Clone() const = 0;
150 };
151 
152 /** Iterator to iterate over a tile area (rectangle) of the map. */
153 class OrthogonalTileIterator : public TileIterator {
154 private:
155 	int w;          ///< The width of the iterated area.
156 	int x;          ///< The current 'x' position in the rectangle.
157 	int y;          ///< The current 'y' position in the rectangle.
158 
159 public:
160 	/**
161 	 * Construct the iterator.
162 	 * @param ta Area, i.e. begin point and width/height of to-be-iterated area.
163 	 */
OrthogonalTileIterator(const OrthogonalTileArea & ta)164 	OrthogonalTileIterator(const OrthogonalTileArea &ta) : TileIterator(ta.w == 0 || ta.h == 0 ? INVALID_TILE : ta.tile), w(ta.w), x(ta.w), y(ta.h)
165 	{
166 	}
167 
168 	/**
169 	 * Construct the iterator.
170 	 * @param corner1 Tile from where to begin iterating.
171 	 * @param corner2 Tile where to end the iterating.
172 	 */
OrthogonalTileIterator(TileIndex corner1,TileIndex corner2)173 	OrthogonalTileIterator(TileIndex corner1, TileIndex corner2)
174 	{
175 		*this = OrthogonalTileIterator(OrthogonalTileArea(corner1, corner2));
176 	}
177 
178 	/**
179 	 * Move ourselves to the next tile in the rectangle on the map.
180 	 */
181 	inline TileIterator& operator ++()
182 	{
183 		assert(this->tile != INVALID_TILE);
184 
185 		if (--this->x > 0) {
186 			this->tile++;
187 		} else if (--this->y > 0) {
188 			this->x = this->w;
189 			this->tile += TileDiffXY(1, 1) - this->w;
190 		} else {
191 			this->tile = INVALID_TILE;
192 		}
193 		return *this;
194 	}
195 
Clone()196 	virtual TileIterator *Clone() const
197 	{
198 		return new OrthogonalTileIterator(*this);
199 	}
200 };
201 
202 /** Iterator to iterate over a diagonal area of the map. */
203 class DiagonalTileIterator : public TileIterator {
204 private:
205 	uint base_x; ///< The base tile x coordinate from where the iterating happens.
206 	uint base_y; ///< The base tile y coordinate from where the iterating happens.
207 	int a_cur;   ///< The current (rotated) x coordinate of the iteration.
208 	int b_cur;   ///< The current (rotated) y coordinate of the iteration.
209 	int a_max;   ///< The (rotated) x coordinate of the end of the iteration.
210 	int b_max;   ///< The (rotated) y coordinate of the end of the iteration.
211 
212 public:
213 
214 	/**
215 	 * Construct the iterator.
216 	 * @param ta Area, i.e. begin point and (diagonal) width/height of to-be-iterated area.
217 	 */
DiagonalTileIterator(const DiagonalTileArea & ta)218 	DiagonalTileIterator(const DiagonalTileArea &ta) :
219 		TileIterator(ta.tile), base_x(TileX(ta.tile)), base_y(TileY(ta.tile)), a_cur(0), b_cur(0), a_max(ta.a), b_max(ta.b)
220 	{
221 	}
222 
223 	/**
224 	 * Construct the iterator.
225 	 * @param corner1 Tile from where to begin iterating.
226 	 * @param corner2 Tile where to end the iterating.
227 	 */
DiagonalTileIterator(TileIndex corner1,TileIndex corner2)228 	DiagonalTileIterator(TileIndex corner1, TileIndex corner2)
229 	{
230 		*this = DiagonalTileIterator(DiagonalTileArea(corner1, corner2));
231 	}
232 
233 	TileIterator& operator ++();
234 
Clone()235 	virtual TileIterator *Clone() const
236 	{
237 		return new DiagonalTileIterator(*this);
238 	}
239 };
240 
241 #endif /* TILEAREA_TYPE_H */
242