1 #include "tileray.h"
2
3 #include <cmath>
4 #include <cstdlib>
5 #include <string>
6
7 #include "line.h"
8 #include "units.h"
9 #include "units_utility.h"
10
11 static const int sx[4] = { 1, -1, -1, 1 };
12 static const int sy[4] = { 1, 1, -1, -1 };
13
14 tileray::tileray() = default;
15
tileray(const point & ad)16 tileray::tileray( const point &ad )
17 {
18 init( ad );
19 }
20
tileray(units::angle adir)21 tileray::tileray( units::angle adir ): direction( adir )
22 {
23 init( adir );
24 }
25
init(const point & ad)26 void tileray::init( const point &ad )
27 {
28 delta = ad;
29 abs_d = delta.abs();
30 if( delta == point_zero ) {
31 direction = 0_degrees;
32 } else {
33 direction = atan2( delta );
34 if( direction < 0_degrees ) {
35 direction += 360_degrees;
36 }
37 }
38 last_d = point_zero;
39 steps = 0;
40 infinite = false;
41 }
42
init(const units::angle & adir)43 void tileray::init( const units::angle &adir )
44 {
45 leftover = 0;
46 // Clamp adir to the range [0, 360)
47 direction = normalize( adir );
48 last_d = point_zero;
49 rl_vec2d delta_f( units::cos( direction ), units::sin( direction ) );
50 delta = ( delta_f * 100 ).as_point();
51 abs_d = delta.abs();
52 steps = 0;
53 infinite = true;
54 }
55
clear_advance()56 void tileray::clear_advance()
57 {
58 leftover = 0;
59 last_d = point_zero;
60 steps = 0;
61 }
62
dx() const63 int tileray::dx() const
64 {
65 return last_d.x;
66 }
67
dy() const68 int tileray::dy() const
69 {
70 return last_d.y;
71 }
72
dir() const73 units::angle tileray::dir() const
74 {
75 return direction;
76 }
77
quadrant() const78 int tileray::quadrant() const
79 {
80 return static_cast<int>( std::floor( direction / 90_degrees ) ) % 4;
81 }
82
dir4() const83 int tileray::dir4() const
84 {
85 if( direction >= 45_degrees && direction <= 135_degrees ) {
86 return 1;
87 } else if( direction > 135_degrees && direction < 225_degrees ) {
88 return 2;
89 } else if( direction >= 225_degrees && direction <= 315_degrees ) {
90 return 3;
91 } else {
92 return 0;
93 }
94 }
95
dir8() const96 int tileray::dir8() const
97 {
98 int oct = 0;
99 units::angle dir = direction;
100 if( dir < 23_degrees || dir > 337_degrees ) {
101 return 0;
102 }
103 while( dir > 22_degrees ) {
104 dir -= 45_degrees;
105 oct += 1;
106 }
107 return oct;
108 }
109
110 // This function assumes a vehicle is being drawn.
111 // It assumes horizontal lines are never skewed, vertical lines often skewed.
dir_symbol(int sym) const112 int tileray::dir_symbol( int sym ) const
113 {
114 switch( sym ) {
115 // output.cpp special_symbol() converts yubn to corners, hj to lines, c to cross
116 case 'j':
117 // vertical line
118 return "h\\j/h\\j/"[dir8()];
119 case 'h':
120 // horizontal line
121 return "jhjh"[dir4()];
122 case 'y':
123 // top left corner
124 return "unby"[dir4()];
125 case 'u':
126 // top right corner
127 return "nbyu"[dir4()];
128 case 'n':
129 // bottom right corner
130 return "byun"[dir4()];
131 case 'b':
132 // bottom left corner
133 return "yunb"[dir4()];
134 case '^':
135 return ">v<^"[dir4()];
136 case '>':
137 return "v<^>"[dir4()];
138 case 'v':
139 return "<^>v"[dir4()];
140 case '<':
141 return "^>v<"[dir4()];
142 case 'c':
143 // +
144 return "cXcXcXcX"[dir8()];
145 case 'X':
146 return "XcXcXcXc"[dir8()];
147
148 case '[':
149 // [ not rotated to ] because they might represent different items
150 return "-\\[/-\\[/"[dir8()];
151 case ']':
152 return "-\\]/-\\]/"[dir8()];
153 case '|':
154 return "-\\|/-\\|/"[dir8()];
155 case '-':
156 return "|/-\\|/-\\"[dir8()];
157 case '=':
158 return "H=H="[dir4()];
159 case 'H':
160 return "=H=H"[dir4()];
161 case '\\':
162 return "/-\\|/-\\|"[dir8()];
163 case '/':
164 return "\\|/-\\|/-"[dir8()];
165 default:
166 ;
167 }
168 return sym;
169 }
170
to_string_azimuth_from_north() const171 std::string tileray::to_string_azimuth_from_north() const
172 {
173 return std::to_string( std::lround( to_degrees( dir() + 90_degrees ) ) % 360 ) + "°";
174 }
175
ortho_dx(int od) const176 int tileray::ortho_dx( int od ) const
177 {
178 od *= -sy[quadrant()];
179 return mostly_vertical() ? od : 0;
180 }
181
ortho_dy(int od) const182 int tileray::ortho_dy( int od ) const
183 {
184 od *= sx[quadrant()];
185 return mostly_vertical() ? 0 : od;
186 }
187
mostly_vertical() const188 bool tileray::mostly_vertical() const
189 {
190 return abs_d.x <= abs_d.y;
191 }
192
advance(int num)193 void tileray::advance( int num )
194 {
195 last_d = point_zero;
196 if( num == 0 ) {
197 return;
198 }
199 int anum = std::abs( num );
200 steps = anum;
201 const bool vertical = mostly_vertical();
202 if( abs_d.x && abs_d.y ) {
203 for( int i = 0; i < anum; i++ ) {
204 if( vertical ) {
205 // mostly vertical line
206 leftover += abs_d.x;
207 if( leftover >= abs_d.y ) {
208 last_d.x++;
209 leftover -= abs_d.y;
210 }
211 } else {
212 // mostly horizontal line
213 leftover += abs_d.y;
214 if( leftover >= abs_d.x ) {
215 last_d.y++;
216 leftover -= abs_d.x;
217 }
218 }
219 }
220 }
221 if( vertical ) {
222 last_d.y = anum;
223 } else {
224 last_d.x = anum;
225 }
226
227 // offset calculated for 0-90 deg quadrant, we need to adjust if direction is other
228 int quadr = quadrant();
229 last_d.x *= sx[quadr];
230 last_d.y *= sy[quadr];
231 if( num < 0 ) {
232 last_d = -last_d;
233 }
234 }
235
end()236 bool tileray::end()
237 {
238 if( infinite ) {
239 return true;
240 }
241 return mostly_vertical() ? steps >= abs_d.y - 1 : steps >= abs_d.x - 1;
242 }
243