1 #pragma once
2
3 /// \file Point.h
4 /// \brief Simple 2D vector with integer coordinates. Provides conversion from and to wxPoint.
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7
8 #include "math/MathUtils.h"
9 #include "objects/Object.h"
10 #include "objects/containers/String.h"
11 #include "objects/utility/IteratorAdapters.h"
12 #include "objects/wrappers/Optional.h"
13 #include <wx/gdicmn.h>
14
15 NAMESPACE_SPH_BEGIN
16
17 template <typename T, typename TDerived>
18 struct BasicPoint {
19 T x, y;
20
21 BasicPoint() = default;
22
BasicPointBasicPoint23 BasicPoint(const T x, const T y)
24 : x(x)
25 , y(y) {}
26
27 T& operator[](const Size index) {
28 SPH_ASSERT(index < 2);
29 return reinterpret_cast<T*>(this)[index];
30 }
31
32 const T& operator[](const Size index) const {
33 SPH_ASSERT(index < 2);
34 return reinterpret_cast<const T*>(this)[index];
35 }
36
37 TDerived& operator+=(const TDerived& other) {
38 x += other.x;
39 y += other.y;
40 return static_cast<TDerived&>(*this);
41 }
42
43 TDerived& operator-=(const TDerived& other) {
44 x -= other.x;
45 y -= other.y;
46 return static_cast<TDerived&>(*this);
47 }
48
49 TDerived& operator*=(const float factor) {
50 x = T(x * factor);
51 y = T(y * factor);
52 return static_cast<TDerived&>(*this);
53 }
54
55 TDerived& operator/=(const float factor) {
56 x = T(x / factor);
57 y = T(y / factor);
58 return static_cast<TDerived&>(*this);
59 }
60
61 TDerived operator+(const TDerived& other) const {
62 TDerived result(static_cast<const TDerived&>(*this));
63 result += other;
64 return result;
65 }
66
67 TDerived operator-(const TDerived& other) const {
68 TDerived result(static_cast<const TDerived&>(*this));
69 result -= other;
70 return result;
71 }
72
73 TDerived operator*(const float factor) const {
74 TDerived result(static_cast<const TDerived&>(*this));
75 result *= factor;
76 return result;
77 }
78
79 TDerived operator/(const float factor) const {
80 TDerived result(static_cast<const TDerived&>(*this));
81 result /= factor;
82 return result;
83 }
84
85 bool operator==(const TDerived& other) const {
86 return x == other.x && y == other.y;
87 }
88
89 bool operator!=(const TDerived& other) const {
90 return !(*this == other);
91 }
92
93 template <typename TStream>
94 friend TStream& operator<<(TStream& stream, const BasicPoint& p) {
95 stream << p.x << " " << p.y;
96 return stream;
97 }
98
99 template <typename TStream>
100 friend TStream& operator>>(TStream& stream, BasicPoint& p) {
101 stream >> p.x >> p.y;
102 return stream;
103 }
104 };
105
106 struct Pixel : public BasicPoint<int, Pixel> {
107 Pixel() = default;
108
PixelPixel109 Pixel(const int x, const int y)
110 : BasicPoint<int, Pixel>(x, y) {}
111
PixelPixel112 explicit Pixel(const wxPoint point)
113 : BasicPoint<int, Pixel>(point.x, point.y) {}
114
wxPointPixel115 explicit operator wxPoint() const {
116 return wxPoint(this->x, this->y);
117 }
118 };
119
120 struct Coords : public BasicPoint<float, Coords> {
121 Coords() = default;
122
CoordsCoords123 Coords(const float x, const float y)
124 : BasicPoint<float, Coords>(x, y) {}
125
CoordsCoords126 explicit Coords(const Pixel p)
127 : BasicPoint<float, Coords>(p.x, p.y) {}
128
129 using BasicPoint<float, Coords>::operator*;
130 using BasicPoint<float, Coords>::operator/;
131
132 Coords operator*(const Coords& other) const {
133 Coords res = *this;
134 res.x *= other.x;
135 res.y *= other.y;
136 return res;
137 }
138
139 Coords operator/(const Coords& other) const {
140 Coords res = *this;
141 SPH_ASSERT(other.x != 0.f && other.y != 0.f);
142 res.x /= other.x;
143 res.y /= other.y;
144 return res;
145 }
146
PixelCoords147 explicit operator Pixel() const {
148 return Pixel(int(x), int(y));
149 }
150
wxPointCoords151 explicit operator wxPoint() const {
152 return wxPoint(int(x), int(y));
153 }
154 };
155
156 template <>
fromString(const String & s)157 INLINE Optional<Pixel> fromString(const String& s) {
158 std::wstringstream ss(s.toUnicode());
159 Pixel p;
160 ss >> p;
161 if (ss) {
162 return p;
163 } else {
164 return NOTHING;
165 }
166 }
167
168 template <typename T, typename TDerived>
getLength(const BasicPoint<T,TDerived> & p)169 INLINE float getLength(const BasicPoint<T, TDerived>& p) {
170 return sqrt(float(sqr(p.x) + sqr(p.y)));
171 }
172
173 class Rectangle {
174 private:
175 Pixel minBound;
176 Pixel maxBound;
177
178 public:
179 Rectangle() = default;
180
Rectangle(const Pixel & lower,const Pixel & upper)181 Rectangle(const Pixel& lower, const Pixel& upper)
182 : minBound(lower)
183 , maxBound(upper) {}
184
window(const Pixel center,const Size radius)185 static Rectangle window(const Pixel center, const Size radius) {
186 return Rectangle(center - Pixel(radius, radius), center + Pixel(radius, radius));
187 }
188
lower()189 Pixel lower() const {
190 return minBound;
191 }
192
upper()193 Pixel upper() const {
194 return maxBound;
195 }
196
size()197 Pixel size() const {
198 return maxBound - minBound;
199 }
200
empty()201 bool empty() const {
202 return maxBound.x < minBound.x || maxBound.y < minBound.y;
203 }
204
contains(const Pixel & p)205 bool contains(const Pixel& p) const {
206 return p.x >= minBound.x && p.y >= minBound.y && p.x <= maxBound.x && p.y <= maxBound.y;
207 }
208
intersect(const Rectangle & other)209 Rectangle intersect(const Rectangle& other) const {
210 Rectangle is;
211 is.minBound.x = max(minBound.x, other.minBound.x);
212 is.minBound.y = max(minBound.y, other.minBound.y);
213 is.maxBound.x = min(maxBound.x, other.maxBound.x);
214 is.maxBound.y = min(maxBound.y, other.maxBound.y);
215 SPH_ASSERT(!is.empty());
216 return is;
217 }
218
colRange()219 IndexSequence colRange() const {
220 return IndexSequence(minBound.x, maxBound.x);
221 }
222
rowRange()223 IndexSequence rowRange() const {
224 return IndexSequence(minBound.y, maxBound.y);
225 }
226 };
227
228 NAMESPACE_SPH_END
229