forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
map_iterator.h
133 lines (112 loc) · 4.46 KB
/
map_iterator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#pragma once
#ifndef CATA_SRC_MAP_ITERATOR_H
#define CATA_SRC_MAP_ITERATOR_H
#include <cstddef>
#include "enums.h"
#include "point.h"
#include "point_traits.h"
template<typename Tripoint>
class tripoint_range
{
static_assert( Tripoint::dimension == 3, "Requires tripoint type" );
private:
using traits = point_traits<Tripoint>;
/**
* Generates points in a rectangle.
*/
class point_generator
{
friend class tripoint_range;
private:
Tripoint p;
const tripoint_range ⦥
public:
using value_type = Tripoint;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
point_generator( const Tripoint &_p, const tripoint_range &_range )
: p( _p ), range( _range ) {
}
// Increment x, then if it goes outside range, "wrap around" and increment y
// Same for y and z
inline point_generator &operator++() {
traits::x( p )++;
if( traits::x( p ) <= traits::x( range.maxp ) ) {
return *this;
}
traits::y( p )++;
traits::x( p ) = traits::x( range.minp );
if( traits::y( p ) <= traits::y( range.maxp ) ) {
return *this;
}
traits::z( p )++;
traits::y( p ) = traits::y( range.minp );
return *this;
}
inline const Tripoint &operator*() const {
return p;
}
inline bool operator!=( const point_generator &other ) const {
// Reverse coordinates order, because it will usually only be compared with endpoint
// which will always differ in Z, except for the very last comparison
// TODO: In C++17 this range should use a sentinel to
// optimise the comparison.
const Tripoint &pt = other.p;
return traits::z( p ) != traits::z( pt ) || p.xy() != pt.xy();
}
inline bool operator==( const point_generator &other ) const {
return !( *this != other );
}
};
Tripoint minp;
Tripoint maxp;
public:
using value_type = typename point_generator::value_type;
using difference_type = typename point_generator::difference_type;
using pointer = typename point_generator::pointer;
using reference = typename point_generator::reference;
using iterator_category = typename point_generator::iterator_category;
tripoint_range( const Tripoint &_minp, const Tripoint &_maxp ) :
minp( _minp ), maxp( _maxp ) {
}
point_generator begin() const {
return point_generator( minp, *this );
}
point_generator end() const {
// Return the point AFTER the last one
// That is, point under (in z-levels) the first one, but one z-level below the last one
return point_generator( Tripoint( minp.xy(), traits::z( maxp ) + 1 ), *this );
}
size_t size() const {
Tripoint range( maxp - minp );
return std::max( ++traits::x( range ) * ++traits::y( range ) * ++traits::z( range ), 0 );
}
bool empty() const {
return size() == 0;
}
bool is_point_inside( const Tripoint &point ) const {
for( const Tripoint ¤t : *this ) {
if( current == point ) {
return true;
}
}
return false;
}
const Tripoint &min() const {
return minp;
}
const Tripoint &max() const {
return maxp;
}
};
template<typename Tripoint>
inline tripoint_range<Tripoint> points_in_radius( const Tripoint ¢er, const int radius,
const int radiusz = 0 )
{
static_assert( Tripoint::dimension == 3, "Requires tripoint type" );
const tripoint offset( radius, radius, radiusz );
return tripoint_range<Tripoint>( center - offset, center + offset );
}
#endif // CATA_SRC_MAP_ITERATOR_H