1 #include "line.h"
2
3 #include <algorithm>
4 #include <array>
5 #include <cstdlib>
6 #include <tuple>
7 #include <utility>
8
9 #include "cata_assert.h"
10 #include "enums.h"
11 #include "math_defines.h"
12 #include "output.h"
13 #include "string_formatter.h"
14 #include "translations.h"
15 #include "units.h"
16 #include "units_fwd.h"
17
18 bool trigdist;
19
iso_tangent(double distance,const units::angle & vertex)20 double iso_tangent( double distance, const units::angle &vertex )
21 {
22 // we can use the cosine formula (a² = b² + c² - 2bc⋅cosθ) to calculate the tangent
23 return std::sqrt( 2 * std::pow( distance, 2 ) * ( 1 - cos( vertex ) ) );
24 }
25
bresenham(const point & p1,const point & p2,int t,const std::function<bool (const point &)> & interact)26 void bresenham( const point &p1, const point &p2, int t,
27 const std::function<bool( const point & )> &interact )
28 {
29 // The slope components.
30 const point d = p2 - p1;
31 // Signs of slope values.
32 const point s( ( d.x == 0 ) ? 0 : sgn( d.x ), ( d.y == 0 ) ? 0 : sgn( d.y ) );
33 // Absolute values of slopes x2 to avoid rounding errors.
34 const point a = d.abs() * 2;
35
36 point cur = p1;
37
38 if( a.x == a.y ) {
39 while( cur.x != p2.x ) {
40 cur.y += s.y;
41 cur.x += s.x;
42 if( !interact( cur ) ) {
43 break;
44 }
45 }
46 } else if( a.x > a.y ) {
47 while( cur.x != p2.x ) {
48 if( t > 0 ) {
49 cur.y += s.y;
50 t -= a.x;
51 }
52 cur.x += s.x;
53 t += a.y;
54 if( !interact( cur ) ) {
55 break;
56 }
57 }
58 } else {
59 while( cur.y != p2.y ) {
60 if( t > 0 ) {
61 cur.x += s.x;
62 t -= a.y;
63 }
64 cur.y += s.y;
65 t += a.x;
66 if( !interact( cur ) ) {
67 break;
68 }
69 }
70 }
71 }
72
bresenham(const tripoint & loc1,const tripoint & loc2,int t,int t2,const std::function<bool (const tripoint &)> & interact)73 void bresenham( const tripoint &loc1, const tripoint &loc2, int t, int t2,
74 const std::function<bool( const tripoint & )> &interact )
75 {
76 // The slope components.
77 const tripoint d( -loc1 + loc2 );
78 // The signs of the slopes.
79 const tripoint s( ( d.x == 0 ? 0 : sgn( d.x ) ), ( d.y == 0 ? 0 : sgn( d.y ) ),
80 ( d.z == 0 ? 0 : sgn( d.z ) ) );
81 // Absolute values of slope components, x2 to avoid rounding errors.
82 const tripoint a( std::abs( d.x ) * 2, std::abs( d.y ) * 2, std::abs( d.z ) * 2 );
83
84 tripoint cur( loc1 );
85
86 if( a.z == 0 ) {
87 if( a.x == a.y ) {
88 while( cur.x != loc2.x ) {
89 cur.y += s.y;
90 cur.x += s.x;
91 if( !interact( cur ) ) {
92 break;
93 }
94 }
95 } else if( a.x > a.y ) {
96 while( cur.x != loc2.x ) {
97 if( t > 0 ) {
98 cur.y += s.y;
99 t -= a.x;
100 }
101 cur.x += s.x;
102 t += a.y;
103 if( !interact( cur ) ) {
104 break;
105 }
106 }
107 } else {
108 while( cur.y != loc2.y ) {
109 if( t > 0 ) {
110 cur.x += s.x;
111 t -= a.y;
112 }
113 cur.y += s.y;
114 t += a.x;
115 if( !interact( cur ) ) {
116 break;
117 }
118 }
119 }
120 } else {
121 if( a.x == a.y && a.y == a.z ) {
122 while( cur.x != loc2.x ) {
123 cur.z += s.z;
124 cur.y += s.y;
125 cur.x += s.x;
126 if( !interact( cur ) ) {
127 break;
128 }
129 }
130 } else if( ( a.z > a.x ) && ( a.z > a.y ) ) {
131 while( cur.z != loc2.z ) {
132 if( t > 0 ) {
133 cur.x += s.x;
134 t -= a.z;
135 }
136 if( t2 > 0 ) {
137 cur.y += s.y;
138 t2 -= a.z;
139 }
140 cur.z += s.z;
141 t += a.x;
142 t2 += a.y;
143 if( !interact( cur ) ) {
144 break;
145 }
146 }
147 } else if( a.x == a.y ) {
148 while( cur.x != loc2.x ) {
149 if( t > 0 ) {
150 cur.z += s.z;
151 t -= a.x;
152 }
153 cur.y += s.y;
154 cur.x += s.x;
155 t += a.z;
156 if( !interact( cur ) ) {
157 break;
158 }
159 }
160 } else if( a.x == a.z ) {
161 while( cur.x != loc2.x ) {
162 if( t > 0 ) {
163 cur.y += s.y;
164 t -= a.x;
165 }
166 cur.z += s.z;
167 cur.x += s.x;
168 t += a.y;
169 if( !interact( cur ) ) {
170 break;
171 }
172 }
173 } else if( a.y == a.z ) {
174 while( cur.y != loc2.y ) {
175 if( t > 0 ) {
176 cur.x += s.x;
177 t -= a.z;
178 }
179 cur.y += s.y;
180 cur.z += s.z;
181 t += a.x;
182 if( !interact( cur ) ) {
183 break;
184 }
185 }
186 } else if( a.x > a.y ) {
187 while( cur.x != loc2.x ) {
188 if( t > 0 ) {
189 cur.y += s.y;
190 t -= a.x;
191 }
192 if( t2 > 0 ) {
193 cur.z += s.z;
194 t2 -= a.x;
195 }
196 cur.x += s.x;
197 t += a.y;
198 t2 += a.z;
199 if( !interact( cur ) ) {
200 break;
201 }
202 }
203 } else { //dy > dx >= dz
204 while( cur.y != loc2.y ) {
205 if( t > 0 ) {
206 cur.x += s.x;
207 t -= a.y;
208 }
209 if( t2 > 0 ) {
210 cur.z += s.z;
211 t2 -= a.y;
212 }
213 cur.y += s.y;
214 t += a.x;
215 t2 += a.z;
216 if( !interact( cur ) ) {
217 break;
218 }
219 }
220 }
221 }
222 }
223
224 //Trying to pull points out of a tripoint vector is messy and
225 //probably slow, so leaving two full functions for now
line_to(const point & p1,const point & p2,int t)226 std::vector<point> line_to( const point &p1, const point &p2, int t )
227 {
228 std::vector<point> line;
229 // Preallocate the number of cells we need instead of allocating them piecewise.
230 const int numCells = square_dist( p1, p2 );
231 if( numCells == 0 ) {
232 line.push_back( p1 );
233 } else {
234 line.reserve( numCells );
235 bresenham( p1, p2, t, [&line]( const point & new_point ) {
236 line.push_back( new_point );
237 return true;
238 } );
239 }
240 return line;
241 }
242
line_to(const tripoint & loc1,const tripoint & loc2,int t,int t2)243 std::vector <tripoint> line_to( const tripoint &loc1, const tripoint &loc2, int t, int t2 )
244 {
245 std::vector<tripoint> line;
246 // Preallocate the number of cells we need instead of allocating them piecewise.
247 const int numCells = square_dist( loc1, loc2 );
248 if( numCells == 0 ) {
249 line.push_back( loc1 );
250 } else {
251 line.reserve( numCells );
252 bresenham( loc1, loc2, t, t2, [&line]( const tripoint & new_point ) {
253 line.push_back( new_point );
254 return true;
255 } );
256 }
257 return line;
258 }
259
rl_dist_exact(const tripoint & loc1,const tripoint & loc2)260 float rl_dist_exact( const tripoint &loc1, const tripoint &loc2 )
261 {
262 if( trigdist ) {
263 return trig_dist( loc1, loc2 );
264 }
265 return square_dist( loc1, loc2 );
266 }
267
manhattan_dist(const point & loc1,const point & loc2)268 int manhattan_dist( const point &loc1, const point &loc2 )
269 {
270 const point d = ( loc1 - loc2 ).abs();
271 return d.x + d.y;
272 }
273
atan2(const point & p)274 units::angle atan2( const point &p )
275 {
276 return units::atan2( p.y, p.x );
277 }
278
279 // This more general version of this function gives correct values for larger values.
make_xyz(const tripoint & p)280 unsigned make_xyz( const tripoint &p )
281 {
282 static constexpr double sixteenth_arc = M_PI / 8;
283 int vertical_position = ( ( p.z > 0 ) ? 2u : ( p.z < 0 ) ? 1u : 0u ) * 9u;
284 if( p.xy() == point_zero ) {
285 return vertical_position;
286 }
287 // Get the arctan of the angle and divide by approximately 22.5 deg to get the octant.
288 // the angle is in, then truncate it and map to the right direction.
289 // You can read 'octant' as being "number of 22.5 degree sections away from due south".
290 // FIXME: atan2 normally takes arguments in ( y, x ) order. This is
291 // passing ( x, y ).
292 int octant = atan2( p.x, p.y ) / sixteenth_arc;
293 switch( octant ) {
294 case 0:
295 return direction::SOUTH + vertical_position;
296 case 1:
297 case 2:
298 return direction::SOUTHEAST + vertical_position;
299 case 3:
300 case 4:
301 return direction::EAST + vertical_position;
302 case 5:
303 case 6:
304 return direction::NORTHEAST + vertical_position;
305 case -1:
306 case -2:
307 return direction::SOUTHWEST + vertical_position;
308 case -3:
309 case -4:
310 return direction::WEST + vertical_position;
311 case -5:
312 case -6:
313 return direction::NORTHWEST + vertical_position;
314 case 7:
315 case 8:
316 case -7:
317 case -8:
318 default:
319 return direction::NORTH + vertical_position;
320 }
321 }
322
323 // returns the normalized dx, dy, dz for the current line vector.
slope_of(const std::vector<tripoint> & line)324 static std::tuple<double, double, double> slope_of( const std::vector<tripoint> &line )
325 {
326 cata_assert( !line.empty() && line.front() != line.back() );
327 const double len = trig_dist( line.front(), line.back() );
328 double normDx = ( line.back().x - line.front().x ) / len;
329 double normDy = ( line.back().y - line.front().y ) / len;
330 double normDz = ( line.back().z - line.front().z ) / len;
331 // slope of <x, y, z>
332 return std::make_tuple( normDx, normDy, normDz );
333 }
334
get_normalized_angle(const point & start,const point & end)335 float get_normalized_angle( const point &start, const point &end )
336 {
337 // Taking the abs value of the difference puts the values in the first quadrant.
338 const float absx = std::abs( std::max( start.x, end.x ) - std::min( start.x, end.x ) );
339 const float absy = std::abs( std::max( start.y, end.y ) - std::min( start.y, end.y ) );
340 const float max = std::max( absx, absy );
341 if( max == 0 ) {
342 return 0;
343 }
344 const float min = std::min( absx, absy );
345 return min / max;
346 }
347
move_along_line(const tripoint & loc,const std::vector<tripoint> & line,const int distance)348 tripoint move_along_line( const tripoint &loc, const std::vector<tripoint> &line,
349 const int distance )
350 {
351 // May want to optimize this, but it's called fairly infrequently as part of specific attack
352 // routines, erring on the side of readability.
353 tripoint res( loc );
354 const auto slope = slope_of( line );
355 res.x += distance * std::get<0>( slope );
356 res.y += distance * std::get<1>( slope );
357 res.z += distance * std::get<2>( slope );
358 return res;
359 }
360
continue_line(const std::vector<tripoint> & line,const int distance)361 std::vector<tripoint> continue_line( const std::vector<tripoint> &line, const int distance )
362 {
363 return line_to( line.back(), move_along_line( line.back(), line, distance ) );
364 }
365
direction_from(const point & p)366 direction direction_from( const point &p ) noexcept
367 {
368 return static_cast<direction>( make_xyz( tripoint( p, 0 ) ) );
369 }
370
direction_from(const tripoint & p)371 direction direction_from( const tripoint &p ) noexcept
372 {
373 return static_cast<direction>( make_xyz( p ) );
374 }
375
direction_from(const point & p1,const point & p2)376 direction direction_from( const point &p1, const point &p2 ) noexcept
377 {
378 return direction_from( p2 - p1 );
379 }
380
direction_from(const tripoint & p,const tripoint & q)381 direction direction_from( const tripoint &p, const tripoint &q )
382 {
383 return direction_from( q - p );
384 }
385
direction_XY(const direction dir)386 point direction_XY( const direction dir )
387 {
388 switch( dir % 9 ) {
389 case direction::NORTHWEST:
390 case direction::ABOVENORTHWEST:
391 case direction::BELOWNORTHWEST:
392 return point_north_west;
393 case direction::NORTH:
394 case direction::ABOVENORTH:
395 case direction::BELOWNORTH:
396 return point_north;
397 case direction::NORTHEAST:
398 case direction::ABOVENORTHEAST:
399 case direction::BELOWNORTHEAST:
400 return point_north_east;
401 case direction::WEST:
402 case direction::ABOVEWEST:
403 case direction::BELOWWEST:
404 return point_west;
405 case direction::CENTER:
406 case direction::ABOVECENTER:
407 case direction::BELOWCENTER:
408 return point_zero;
409 case direction::EAST:
410 case direction::ABOVEEAST:
411 case direction::BELOWEAST:
412 return point_east;
413 case direction::SOUTHWEST:
414 case direction::ABOVESOUTHWEST:
415 case direction::BELOWSOUTHWEST:
416 return point_south_west;
417 case direction::SOUTH:
418 case direction::ABOVESOUTH:
419 case direction::BELOWSOUTH:
420 return point_south;
421 case direction::SOUTHEAST:
422 case direction::ABOVESOUTHEAST:
423 case direction::BELOWSOUTHEAST:
424 return point_south_east;
425 }
426
427 return point_zero;
428 }
429
430 namespace
431 {
direction_name_impl(const direction dir,const bool short_name)432 std::string direction_name_impl( const direction dir, const bool short_name )
433 {
434 enum : int { size = 3 * 3 * 3 };
435 static const auto names = [] {
436 using pair_t = std::pair<std::string, std::string>;
437 std::array < pair_t, size + 1 > result;
438
439 //~ abbreviated direction names and long direction names
440 result[static_cast<size_t>( direction::NORTH )] = pair_t {translate_marker( "N " ), translate_marker( "north" )};
441 result[static_cast<size_t>( direction::NORTHEAST )] = pair_t {translate_marker( "NE " ), translate_marker( "northeast" )};
442 result[static_cast<size_t>( direction::EAST )] = pair_t {translate_marker( "E " ), translate_marker( "east" )};
443 result[static_cast<size_t>( direction::SOUTHEAST )] = pair_t {translate_marker( "SE " ), translate_marker( "southeast" )};
444 result[static_cast<size_t>( direction::SOUTH )] = pair_t {translate_marker( "S " ), translate_marker( "south" )};
445 result[static_cast<size_t>( direction::SOUTHWEST )] = pair_t {translate_marker( "SW " ), translate_marker( "southwest" )};
446 result[static_cast<size_t>( direction::WEST )] = pair_t {translate_marker( "W " ), translate_marker( "west" )};
447 result[static_cast<size_t>( direction::NORTHWEST )] = pair_t {translate_marker( "NW " ), translate_marker( "northwest" )};
448 result[static_cast<size_t>( direction::ABOVENORTH )] = pair_t {translate_marker( "UP_N " ), translate_marker( "north and above" )};
449 result[static_cast<size_t>( direction::ABOVENORTHEAST )] = pair_t {translate_marker( "UP_NE" ), translate_marker( "northeast and above" )};
450 result[static_cast<size_t>( direction::ABOVEEAST )] = pair_t {translate_marker( "UP_E " ), translate_marker( "east and above" )};
451 result[static_cast<size_t>( direction::ABOVESOUTHEAST )] = pair_t {translate_marker( "UP_SE" ), translate_marker( "southeast and above" )};
452 result[static_cast<size_t>( direction::ABOVESOUTH )] = pair_t {translate_marker( "UP_S " ), translate_marker( "south and above" )};
453 result[static_cast<size_t>( direction::ABOVESOUTHWEST )] = pair_t {translate_marker( "UP_SW" ), translate_marker( "southwest and above" )};
454 result[static_cast<size_t>( direction::ABOVEWEST )] = pair_t {translate_marker( "UP_W " ), translate_marker( "west and above" )};
455 result[static_cast<size_t>( direction::ABOVENORTHWEST )] = pair_t {translate_marker( "UP_NW" ), translate_marker( "northwest and above" )};
456 result[static_cast<size_t>( direction::BELOWNORTH )] = pair_t {translate_marker( "DN_N " ), translate_marker( "north and below" )};
457 result[static_cast<size_t>( direction::BELOWNORTHEAST )] = pair_t {translate_marker( "DN_NE" ), translate_marker( "northeast and below" )};
458 result[static_cast<size_t>( direction::BELOWEAST )] = pair_t {translate_marker( "DN_E " ), translate_marker( "east and below" )};
459 result[static_cast<size_t>( direction::BELOWSOUTHEAST )] = pair_t {translate_marker( "DN_SE" ), translate_marker( "southeast and below" )};
460 result[static_cast<size_t>( direction::BELOWSOUTH )] = pair_t {translate_marker( "DN_S " ), translate_marker( "south and below" )};
461 result[static_cast<size_t>( direction::BELOWSOUTHWEST )] = pair_t {translate_marker( "DN_SW" ), translate_marker( "southwest and below" )};
462 result[static_cast<size_t>( direction::BELOWWEST )] = pair_t {translate_marker( "DN_W " ), translate_marker( "west and below" )};
463 result[static_cast<size_t>( direction::BELOWNORTHWEST )] = pair_t {translate_marker( "DN_NW" ), translate_marker( "northwest and below" )};
464 result[static_cast<size_t>( direction::ABOVECENTER )] = pair_t {translate_marker( "UP_CE" ), translate_marker( "above" )};
465 result[static_cast<size_t>( direction::CENTER )] = pair_t {translate_marker( "CE " ), translate_marker( "center" )};
466 result[static_cast<size_t>( direction::BELOWCENTER )] = pair_t {translate_marker( "DN_CE" ), translate_marker( "below" )};
467
468 result[size] = pair_t {"BUG. (line.cpp:direction_name)", "BUG. (line.cpp:direction_name)"};
469 return result;
470 }();
471
472 int i = static_cast<int>( dir );
473 if( i < 0 || i >= size ) {
474 i = size;
475 }
476
477 return short_name ? _( names[i].first ) : _( names[i].second );
478 }
479 } //namespace
480
direction_name(const direction dir)481 std::string direction_name( const direction dir )
482 {
483 return direction_name_impl( dir, false );
484 }
485
direction_name_short(const direction dir)486 std::string direction_name_short( const direction dir )
487 {
488 return direction_name_impl( dir, true );
489 }
490
direction_suffix(const tripoint & p,const tripoint & q)491 std::string direction_suffix( const tripoint &p, const tripoint &q )
492 {
493 int dist = square_dist( p, q );
494 if( dist <= 0 ) {
495 return std::string();
496 }
497 return string_format( "%d%s", dist, trim( direction_name_short( direction_from( p, q ) ) ) );
498 }
499
500 // Cardinals are cardinals. Result is cardinal and adjacent sub-cardinals.
501 // Sub-Cardinals are sub-cardinals && abs(x) == abs(y). Result is sub-cardinal and adjacent cardinals.
502 // Sub-sub-cardinals are direction && abs(x) > abs(y) or vice versa.
503 // Result is adjacent cardinal and sub-cardinals, plus the nearest other cardinal.
504 // e.g. if the direction is NNE, also include E.
squares_closer_to(const tripoint & from,const tripoint & to)505 std::vector<tripoint> squares_closer_to( const tripoint &from, const tripoint &to )
506 {
507 std::vector<tripoint> adjacent_closer_squares;
508 adjacent_closer_squares.reserve( 5 );
509 const tripoint d( -from + to );
510 const point a( std::abs( d.x ), std::abs( d.y ) );
511 if( d.z != 0 ) {
512 adjacent_closer_squares.push_back( from + tripoint( sgn( d.x ), sgn( d.y ), sgn( d.z ) ) );
513 }
514 if( a.x > a.y ) {
515 // X dominant.
516 adjacent_closer_squares.push_back( from + point( sgn( d.x ), 0 ) );
517 adjacent_closer_squares.push_back( from + point( sgn( d.x ), 1 ) );
518 adjacent_closer_squares.push_back( from + point( sgn( d.x ), -1 ) );
519 if( d.y != 0 ) {
520 adjacent_closer_squares.push_back( from + point( 0, sgn( d.y ) ) );
521 }
522 } else if( a.x < a.y ) {
523 // Y dominant.
524 adjacent_closer_squares.push_back( from + point( 0, sgn( d.y ) ) );
525 adjacent_closer_squares.push_back( from + point( 1, sgn( d.y ) ) );
526 adjacent_closer_squares.push_back( from + point( -1, sgn( d.y ) ) );
527 if( d.x != 0 ) {
528 adjacent_closer_squares.push_back( from + point( sgn( d.x ), 0 ) );
529 }
530 } else if( d.x != 0 ) {
531 // Pure diagonal.
532 adjacent_closer_squares.push_back( from + point( sgn( d.x ), sgn( d.y ) ) );
533 adjacent_closer_squares.push_back( from + point( sgn( d.x ), 0 ) );
534 adjacent_closer_squares.push_back( from + point( 0, sgn( d.y ) ) );
535 }
536
537 return adjacent_closer_squares;
538 }
539
540 // Returns a vector of the adjacent square in the direction of the target,
541 // and the two squares flanking it.
squares_in_direction(const point & p1,const point & p2)542 std::vector<point> squares_in_direction( const point &p1, const point &p2 )
543 {
544 int junk = 0;
545 point center_square = line_to( p1, p2, junk )[0];
546 std::vector<point> adjacent_squares;
547 adjacent_squares.reserve( 3 );
548 adjacent_squares.push_back( center_square );
549 if( p1.x == center_square.x ) {
550 // Horizontally adjacent.
551 adjacent_squares.push_back( point( p1.x + 1, center_square.y ) );
552 adjacent_squares.push_back( point( p1.x - 1, center_square.y ) );
553 } else if( p1.y == center_square.y ) {
554 // Vertically adjacent.
555 adjacent_squares.push_back( point( center_square.x, p1.y + 1 ) );
556 adjacent_squares.push_back( point( center_square.x, p1.y - 1 ) );
557 } else {
558 // Diagonally adjacent.
559 adjacent_squares.push_back( point( p1.x, center_square.y ) );
560 adjacent_squares.push_back( point( center_square.x, p1.y ) );
561 }
562 return adjacent_squares;
563 }
564
magnitude() const565 float rl_vec2d::magnitude() const
566 {
567 return std::sqrt( x * x + y * y );
568 }
569
magnitude() const570 float rl_vec3d::magnitude() const
571 {
572 return std::sqrt( x * x + y * y + z * z );
573 }
574
normalized() const575 rl_vec2d rl_vec2d::normalized() const
576 {
577 rl_vec2d ret;
578 if( is_null() ) { // shouldn't happen?
579 ret.x = ret.y = 1;
580 return ret;
581 }
582 const float m = magnitude();
583 ret.x = x / m;
584 ret.y = y / m;
585 return ret;
586 }
587
normalized() const588 rl_vec3d rl_vec3d::normalized() const
589 {
590 rl_vec3d ret;
591 if( is_null() ) { // shouldn't happen?
592 ret.x = ret.y = ret.z = 0;
593 return ret;
594 }
595 const float m = magnitude();
596 ret.x = x / m;
597 ret.y = y / m;
598 ret.z = z / m;
599 return ret;
600 }
601
rotated(float angle) const602 rl_vec2d rl_vec2d::rotated( float angle ) const
603 {
604 return rl_vec2d(
605 x * std::cos( angle ) - y * std::sin( angle ),
606 x * std::sin( angle ) + y * std::cos( angle )
607 );
608 }
609
rotated(float angle) const610 rl_vec3d rl_vec3d::rotated( float angle ) const
611 {
612 return rl_vec3d(
613 x * std::cos( angle ) - y * std::sin( angle ),
614 x * std::sin( angle ) + y * std::cos( angle )
615 );
616 }
617
dot_product(const rl_vec2d & v) const618 float rl_vec2d::dot_product( const rl_vec2d &v ) const
619 {
620 return x * v.x + y * v.y;
621 }
622
dot_product(const rl_vec3d & v) const623 float rl_vec3d::dot_product( const rl_vec3d &v ) const
624 {
625 return x * v.x + y * v.y + y * v.z;
626 }
627
is_null() const628 bool rl_vec2d::is_null() const
629 {
630 return !( x || y );
631 }
632
as_point() const633 point rl_vec2d::as_point() const
634 {
635 return point(
636 std::round( x ),
637 std::round( y )
638 );
639 }
640
is_null() const641 bool rl_vec3d::is_null() const
642 {
643 return !( x || y || z );
644 }
645
as_point() const646 tripoint rl_vec3d::as_point() const
647 {
648 return tripoint(
649 std::round( x ),
650 std::round( y ),
651 std::round( z )
652 );
653 }
654
655 // scale.
operator *(const float rhs) const656 rl_vec2d rl_vec2d::operator*( const float rhs ) const
657 {
658 rl_vec2d ret;
659 ret.x = x * rhs;
660 ret.y = y * rhs;
661 return ret;
662 }
663
operator *(const float rhs) const664 rl_vec3d rl_vec3d::operator*( const float rhs ) const
665 {
666 rl_vec3d ret;
667 ret.x = x * rhs;
668 ret.y = y * rhs;
669 ret.z = z * rhs;
670 return ret;
671 }
672
673 // subtract
operator -(const rl_vec2d & rhs) const674 rl_vec2d rl_vec2d::operator-( const rl_vec2d &rhs ) const
675 {
676 rl_vec2d ret;
677 ret.x = x - rhs.x;
678 ret.y = y - rhs.y;
679 return ret;
680 }
681
operator -(const rl_vec3d & rhs) const682 rl_vec3d rl_vec3d::operator-( const rl_vec3d &rhs ) const
683 {
684 rl_vec3d ret;
685 ret.x = x - rhs.x;
686 ret.y = y - rhs.y;
687 ret.z = z - rhs.z;
688 return ret;
689 }
690
691 // unary negation
operator -() const692 rl_vec2d rl_vec2d::operator-() const
693 {
694 rl_vec2d ret;
695 ret.x = -x;
696 ret.y = -y;
697 return ret;
698 }
699
operator -() const700 rl_vec3d rl_vec3d::operator-() const
701 {
702 rl_vec3d ret;
703 ret.x = -x;
704 ret.y = -y;
705 ret.z = -z;
706 return ret;
707 }
708
operator +(const rl_vec2d & rhs) const709 rl_vec2d rl_vec2d::operator+( const rl_vec2d &rhs ) const
710 {
711 rl_vec2d ret;
712 ret.x = x + rhs.x;
713 ret.y = y + rhs.y;
714 return ret;
715 }
716
operator +(const rl_vec3d & rhs) const717 rl_vec3d rl_vec3d::operator+( const rl_vec3d &rhs ) const
718 {
719 rl_vec3d ret;
720 ret.x = x + rhs.x;
721 ret.y = y + rhs.y;
722 ret.z = z + rhs.z;
723 return ret;
724 }
725
operator /(const float rhs) const726 rl_vec2d rl_vec2d::operator/( const float rhs ) const
727 {
728 rl_vec2d ret;
729 ret.x = x / rhs;
730 ret.y = y / rhs;
731 return ret;
732 }
733
operator /(const float rhs) const734 rl_vec3d rl_vec3d::operator/( const float rhs ) const
735 {
736 rl_vec3d ret;
737 ret.x = x / rhs;
738 ret.y = y / rhs;
739 ret.z = z / rhs;
740 return ret;
741 }
742
calc_ray_end(units::angle angle,const int range,const tripoint & p,tripoint & out)743 void calc_ray_end( units::angle angle, const int range, const tripoint &p, tripoint &out )
744 {
745 // forces input angle to be between 0 and 360, calculated from actual input
746 angle = fmod( angle, 360_degrees );
747 if( angle < 0_degrees ) {
748 angle += 360_degrees;
749 }
750 out.z = p.z;
751 if( trigdist ) {
752 out.x = p.x + range * cos( angle );
753 out.y = p.y + range * sin( angle );
754 } else {
755 int mult = 0;
756 if( angle >= 135_degrees && angle <= 315_degrees ) {
757 mult = -1;
758 } else {
759 mult = 1;
760 }
761
762 if( angle <= 45_degrees || ( 135_degrees <= angle && angle <= 215_degrees ) ||
763 315_degrees < angle ) {
764 out.x = p.x + range * mult;
765 out.y = p.y + range * tan( angle ) * mult;
766 } else {
767 out.x = p.x + range * 1 / tan( angle ) * mult;
768 out.y = p.y + range * mult;
769 }
770 }
771 }
772
coord_to_angle(const tripoint & a,const tripoint & b)773 units::angle coord_to_angle( const tripoint &a, const tripoint &b )
774 {
775 units::angle rad = units::atan2( b.y - a.y, b.x - a.x );
776 if( rad < 0_degrees ) {
777 rad += 2_pi_radians;
778 }
779 return rad;
780 }
781