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