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