1 /*
2 * Copyright (c) 1997 - 2002 Hj. Malthaner
3 *
4 * This file is part of the Simutrans project under the artisic licence.
5 * (see licence.txt)
6 */
7
8 #ifndef dataobj_ribi_t_h
9 #define dataobj_ribi_t_h
10
11 #include "../simtypes.h"
12 #include "../simconst.h"
13 #include "../simdebug.h"
14
15 class koord;
16 class koord3d;
17
18 /**
19 * Slopes of tiles.
20 */
21 class slope_t {
22
23 /// Static lookup table
24 static const int flags[81];
25
26 /// Named constants for the flags table
27 enum {
28 doubles = 1, ///< two-height difference slopes
29 way_ns = 2, ///< way possible in north-south direction
30 way_ew = 4, ///< way possible in east-west direction
31 single = 8, ///< way possible
32 all_up = 16, ///< all corners raised
33 };
34
35 public:
36
37 typedef sint8 type;
38
39 /*
40 * Macros to access the height of the 4 corners:
41 * Each corner has height 0,1,2.
42 * Calculation has to be done modulo 3 (% 3).
43 */
44 #define corner_sw(i) (i%3) // sw corner
45 #define corner_se(i) ((i/3)%3) // se corner
46 #define corner_ne(i) ((i/9)%3) // ne corner
47 #define corner_nw(i) (i/27) // nw corner
48
49 /**
50 * Named constants for special cases.
51 */
52 enum _type {
53 flat=0,
54 north = 3+1, ///< North slope
55 west = 9+3, ///< West slope
56 east = 27+1, ///< East slope
57 south = 27+9, ///< South slope
58 northwest = 27, ///< NW corner
59 northeast = 9, ///< NE corner
60 southeast = 3, ///< SE corner
61 southwest = 1, ///< SW corner
62 raised = 80, ///< special meaning: used as slope of bridgeheads and in terraforming tools
63 };
64
65
66 /// Compute the slope opposite to @p x. Returns flat if @p x does not allow ways on it.
opposite(type x)67 static type opposite(type x) { return is_single(x) ? (x & 7 ? (40 - x) : (80 - x * 2)) : flat; }
68 /// Rotate.
rotate90(type x)69 static type rotate90(type x) { return ( ( (x % 3) * 27 ) + ( ( x - (x % 3) ) / 3 ) ); }
70 /// Returns true if @p x has all corners raised.
is_all_up(type x)71 static bool is_all_up(type x) { return (flags[x] & all_up)>0; }
72 /// Returns maximal height difference between the corners of this slope.
max_diff(type x)73 static uint8 max_diff(type x) { return (x!=0)+(flags[x]&doubles); }
74 /// Computes minimum height differnce between corners of @p high and @p low.
min_diff(type high,type low)75 static sint8 min_diff(type high, type low) { return min( min( corner_sw(high) - corner_sw(low), corner_se(high)-corner_se(low) ), min( corner_ne(high) - corner_ne(low), corner_nw(high) - corner_nw(low) ) ); }
76
77 /// Returns if slope prefers certain way directions (either n/s or e/w).
is_single(type x)78 static bool is_single(type x) { return (flags[x] & single) != 0; }
79 /// Returns if way can be build on this slope.
is_way(type x)80 static bool is_way(type x) { return (flags[x] & (way_ns | way_ew)) != 0; }
81 /// Returns if way in n/s direction can be build on this slope.
is_way_ns(type x)82 static bool is_way_ns(type x) { return (flags[x] & way_ns) != 0; }
83 /// Returns if way in e/w direction can be build on this slope.
is_way_ew(type x)84 static bool is_way_ew(type x) { return (flags[x] & way_ew) != 0; }
85 };
86
87
88 /**
89 * Old implementation of slopes: one bit per corner.
90 * Used as bitfield to refer to specific corners of a tile
91 * as well as for compatibility.
92 */
93 struct slope4_t {
94 /* bit-field:
95 * Bit 0 is set if southwest corner is raised
96 * Bit 1 is set if southeast corner is raised
97 * Bit 2 is set if northeast corner is raised
98 * Bit 3 is set if northwest corner is raised
99 *
100 * Don't get confused - the southern/southward slope has its northern corners raised
101 *
102 * Macros to access the height of the 4 corners for single slope:
103 * One bit per corner
104 */
105 typedef sint8 type;
106
107 #define scorner_sw(i) (i%2) // sw corner
108 #define scorner_se(i) ((i/2)%2) // se corner
109 #define scorner_ne(i) ((i/4)%2) // ne corner
110 #define scorner_nw(i) (i/8) // nw corner
111 enum _corners {
112 corner_SW = 1,
113 corner_SE = 2,
114 corner_NE = 4,
115 corner_NW = 8
116 };
117 };
118
119
120 /**
121 * Directions in simutrans.
122 * ribi_t = Richtungs-Bit = Directions-Bitfield
123 * @author Hj. Malthaner
124 */
125 class ribi_t {
126 /// Static lookup table
127 static const int flags[16];
128
129 /// Named constants for properties of directions
130 enum {
131 single = 1, ///< only one bit set, way ends here
132 straight_ns = 2, ///< contains straight n/s connection
133 straight_ew = 4, ///< contains straight e/w connection
134 bend = 8, ///< is a bend
135 twoway = 16, ///< two bits set
136 threeway = 32, ///< three bits set
137 };
138
139 public:
140 /**
141 * Named constants for all possible directions.
142 * 1=North, 2=East, 4=South, 8=West
143 */
144 enum _ribi {
145 none =0,
146 north = 1,
147 east = 2,
148 northeast = 3,
149 south = 4,
150 northsouth = 5,
151 southeast = 6,
152 northsoutheast = 7,
153 west = 8,
154 northwest = 9,
155 eastwest = 10,
156 northeastwest = 11,
157 southwest = 12,
158 northsouthwest = 13,
159 southeastwest = 14,
160 all = 15
161 };
162 typedef uint8 ribi;
163
164 /**
165 * Named constants to translate direction to image number for vehicles, signs.
166 */
167 enum _dir {
168 dir_invalid = 0,
169 dir_south = 0,
170 dir_west = 1,
171 dir_southwest = 2,
172 dir_southeast = 3,
173 dir_north = 4,
174 dir_east = 5,
175 dir_northeast = 6,
176 dir_northwest = 7
177 };
178 typedef uint8 dir;
179
180 private:
181 /// Lookup table to compute backward direction
182 static const ribi backwards[16];
183 /// Lookup table ...
184 static const ribi doppelr[16];
185 /// Lookup table to convert ribi to dir.
186 static const dir dirs[16];
187 public:
188 /// Table containing the four compass directions
189 static const ribi nsew[4];
190 /// Convert building layout to ribi (four rotations), use doppelt in case of two rotations
191 static const ribi layout_to_ribi[4]; // building layout to ribi (for four rotations, for two use doppelt()!
192
is_twoway(ribi x)193 static bool is_twoway(ribi x) { return (flags[x]&twoway)!=0; }
is_threeway(ribi x)194 static bool is_threeway(ribi x) { return (flags[x]&threeway)!=0; }
195 static bool is_perpendicular(ribi x, ribi y);
is_single(ribi x)196 static bool is_single(ribi x) { return (flags[x] & single) != 0; }
is_bend(ribi x)197 static bool is_bend(ribi x) { return (flags[x] & bend) != 0; }
is_straight(ribi x)198 static bool is_straight(ribi x) { return (flags[x] & (straight_ns | straight_ew)) != 0; }
is_straight_ns(ribi x)199 static bool is_straight_ns(ribi x) { return (flags[x] & straight_ns) != 0; }
is_straight_ew(ribi x)200 static bool is_straight_ew(ribi x) { return (flags[x] & straight_ew) != 0; }
201
202 /// Convert single/straight direction into their doubled form (n, ns -> ns), map all others to zero
doubles(ribi x)203 static ribi doubles(ribi x) { return doppelr[x]; }
204 /// Backward direction for single ribi's, bitwise-NOT for all others
backward(ribi x)205 static ribi backward(ribi x) { return backwards[x]; }
206
207 /**
208 * Same as backward, but for single directions only.
209 * Effectively does bit rotation. Avoids lookup table backwards.
210 * @returns backward(x) for single ribis, 0 for x==0.
211 */
reverse_single(ribi x)212 static inline ribi reverse_single(ribi x) {
213 return ((x | x<<4) >> 2) & 0xf;
214 }
215
216 /// Rotate 90 degrees to the right. Does bit rotation.
rotate90(ribi x)217 static ribi rotate90(ribi x) { return ((x | x<<4) >> 3) & 0xf; }
218 /// Rotate 90 degrees to the left. Does bit rotation.
rotate90l(ribi x)219 static ribi rotate90l(ribi x) { return ((x | x<<4) >> 1) & 0xf; }
rotate45(ribi x)220 static ribi rotate45(ribi x) { return (is_single(x) ? x|rotate90(x) : x&rotate90(x)); } // 45 to the right
rotate45l(ribi x)221 static ribi rotate45l(ribi x) { return (is_single(x) ? x|rotate90l(x) : x&rotate90l(x)); } // 45 to the left
222
223 /// Convert ribi to dir
get_dir(ribi x)224 static dir get_dir(ribi x) { return dirs[x]; }
225 };
226
227 /**
228 * Calculate slope from directions.
229 * Go upward on the slope: going north translates to slope_t::south.
230 */
231 slope_t::type slope_type(koord dir);
232
233 /**
234 * Calculate slope from directions.
235 * Go upward on the slope: going north translates to slope_t::south.
236 */
237 slope_t::type slope_type(ribi_t::ribi);
238
239 /**
240 * Check if the slope is upwards, relative to the direction @p from.
241 * @returns 1 for single upwards and 2 for double upwards
242 */
243 sint16 get_sloping_upwards(const slope_t::type slope, const ribi_t::ribi from);
244
245 /**
246 * Calculate direction bit from coordinate differences.
247 */
248 ribi_t::ribi ribi_typ_intern(sint16 dx, sint16 dy);
249
250 /**
251 * Calculate direction bit from direction.
252 */
253 ribi_t::ribi ribi_type(const koord& dir);
254 ribi_t::ribi ribi_type(const koord3d& dir);
255
256 /**
257 * Calculate direction bit from slope.
258 * Note: slope_t::north (slope north) will be translated to ribi_t::south (direction south).
259 */
260 ribi_t::ribi ribi_type(slope_t::type slope);
261
262 /**
263 * Calculate direction bit for travel from @p from to @p to.
264 */
265 template<class K1, class K2>
ribi_type(const K1 & from,const K2 & to)266 ribi_t::ribi ribi_type(const K1&from, const K2& to)
267 {
268 return ribi_typ_intern(to.x - from.x, to.y - from.y);
269 }
270
271 #endif
272