C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
rect.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <algorithm>
26#include <compare>
27#include <cstdint>
28#include <limits>
29#include <type_traits>
30#include <utility>
31
32namespace essence {
33 template <typename T>
34 requires std::is_arithmetic_v<T>
36 T value;
37
38 constexpr implicit_number_casting_operator(T value) noexcept : value{value} {} // NOLINT(*-explicit-constructor)
39
40 template <typename U>
41 constexpr operator U() const noexcept // NOLINT(*-explicit-constructor)
42 requires std::is_arithmetic_v<U>
43 {
44 return static_cast<U>(value);
45 }
46 };
47
48 template <typename T>
49 concept equivalent_rect = std::is_aggregate_v<T> && requires(T obj) {
50 requires std::is_arithmetic_v<decltype(obj.x)>;
51 requires std::is_arithmetic_v<decltype(obj.y)>;
52 requires std::is_arithmetic_v<decltype(obj.width)>;
53 requires std::is_arithmetic_v<decltype(obj.height)>;
54 T{
55 .x = {},
56 .y = {},
57 .width = {},
58 .height = {},
59 };
60 };
61
62 template <typename T>
63 concept bottom_right_rect = std::is_aggregate_v<T> && requires(T obj) {
64 requires std::is_arithmetic_v<decltype(obj.left)>;
65 requires std::is_arithmetic_v<decltype(obj.top)>;
66 requires std::is_arithmetic_v<decltype(obj.right)>;
67 requires std::is_arithmetic_v<decltype(obj.bottom)>;
68 T{
69 .left = {},
70 .top = {},
71 .right = {},
72 .bottom = {},
73 };
74 };
75
76 template <typename T>
77 concept width_height_pair = std::is_aggregate_v<T> && requires(T obj) {
78 requires std::is_arithmetic_v<decltype(obj.width)>;
79 requires std::is_arithmetic_v<decltype(obj.height)>;
80 T{
81 .width = {},
82 .height = {},
83 };
84 };
85
86 template <typename T>
87 concept nothrow_equivalent_rect = requires {
88 requires equivalent_rect<T>;
89 {
90 T{
91 .x = {},
92 .y = {},
93 .width = {},
94 .height = {},
95 }
96 } noexcept;
97 };
98
99 template <typename T>
100 concept nothrow_bottom_right_rect = requires {
101 requires bottom_right_rect<T>;
102 {
103 T{
104 .left = {},
105 .top = {},
106 .right = {},
107 .bottom = {},
108 }
109 } noexcept;
110 };
111
112 template <typename T>
113 concept nothrow_width_height_pair = requires {
114 requires width_height_pair<T>;
115 {
116 T{
117 .width = {},
118 .height = {},
119 }
120 } noexcept;
121 };
122
126 enum class rect_ratio_base {
130 left,
134 right,
138 smaller,
139 };
140
145 template <typename Number>
146 requires std::is_arithmetic_v<Number>
147 struct rect {
148 Number x{};
149 Number y{};
150 Number width{};
151 Number height{};
152
153 constexpr auto operator<=>(const rect&) const noexcept = default;
154
155 constexpr Number right() const noexcept {
156 return x + width;
157 }
158
159 constexpr Number bottom() const noexcept {
160 return y + height;
161 }
162
163 constexpr Number area() const noexcept {
164 return width * height;
165 }
166
171 template <typename T>
172 constexpr operator T() const // NOLINT(*-explicit-constructor)
173 noexcept(nothrow_bottom_right_rect<std::decay_t<T>>) // NOLINT(*-explicit-constructor)
174 requires bottom_right_rect<std::decay_t<T>>
175 {
176 return std::decay_t<T>{
179 .right = implicit_number_casting_operator{right()},
180 .bottom = implicit_number_casting_operator{bottom()},
181 };
182 }
183
188 template <typename T>
189 constexpr operator T() const // NOLINT(*-explicit-constructor)
190 noexcept(nothrow_equivalent_rect<std::decay_t<T>>) // NOLINT(*-explicit-constructor)
191 requires equivalent_rect<std::decay_t<T>>
192 {
193 return std::decay_t<T>{
196 .width = implicit_number_casting_operator{width},
197 .height = implicit_number_casting_operator{height},
198 };
199 }
200
206 template <width_height_pair T>
207 constexpr T to_extent() const noexcept(nothrow_width_height_pair<T>) {
208 return T{
209 .width = implicit_number_casting_operator{width},
210 .height = implicit_number_casting_operator{height},
211 };
212 }
213
219 template <width_height_pair T>
220 constexpr void assign_from_extent(const T& pair) noexcept {
221 width = implicit_number_casting_operator{pair.width};
222 height = implicit_number_casting_operator{pair.height};
223 }
224
229 [[nodiscard]] constexpr bool collapsed() const noexcept {
230 return width <= std::numeric_limits<Number>::epsilon() || height <= std::numeric_limits<Number>::epsilon();
231 }
232
239 template <bottom_right_rect T>
248
255 template <equivalent_rect T>
256 static constexpr rect from(const T& equivalent_rect) noexcept {
257 return rect{
262 };
263 }
264 };
265
273 template <typename T>
274 requires std::is_arithmetic_v<T>
275 constexpr bool intersect_with(const rect<T>& left, const rect<T>& right) noexcept {
276 return std::max(left.x, right.x) <= std::min(left.right(), right.right())
277 && std::max(left.y, right.y) <= std::min(left.bottom(), right.bottom());
278 }
279
287 template <typename T>
288 requires std::is_arithmetic_v<T>
289 constexpr T calc_overlapped_area(const rect<T>& left, const rect<T>& right) noexcept {
290 auto dx = std::min(left.right(), right.right()) - std::max(left.x, right.x);
291 auto dy = std::min(left.bottom(), right.bottom()) - std::max(left.y, right.y);
292
293 return dx >= 0 && dy >= 0 ? dx * dy : 0;
294 }
295
304 template <typename T>
305 requires std::is_arithmetic_v<T>
306 constexpr double calc_overlapped_ratio(
307 const rect<T>& left, const rect<T>& right, rect_ratio_base ratio_base) noexcept {
308 auto area = static_cast<double>(calc_overlapped_area(left, right));
309
310 switch (ratio_base) {
311 case rect_ratio_base::left:
312 return area / left.area();
313 case rect_ratio_base::right:
314 return area / right.area();
315 case rect_ratio_base::smaller:
316 return area / std::min(left.area(), right.area());
317 default:
318 return 0.0;
319 }
320 }
321
322 using recti = rect<std::int32_t>;
323 using rectf = rect<float>;
324 using rectd = rect<double>;
325} // namespace essence
Definition rect.hpp:63
Definition rect.hpp:49
Definition rect.hpp:100
Definition rect.hpp:87
Definition rect.hpp:113
Definition rect.hpp:77
Illustrates a rectangle.
Definition rect.hpp:147
static constexpr rect from(const T &bottom_right_rect) noexcept
Makes a rectangle from a compatible rectangle that contains member variables x, y,...
Definition rect.hpp:240
static constexpr rect from(const T &equivalent_rect) noexcept
Makes a rectangle from an equivalent rectangle that contains member variables x, y,...
Definition rect.hpp:256
constexpr bool collapsed() const noexcept
Checks whether the area of the rectangle is zero (i.e. collapsed to a zero-dimensional point).
Definition rect.hpp:229
constexpr T to_extent() const noexcept(nothrow_width_height_pair< T >)
Retrieves the width-height pair.
Definition rect.hpp:207
constexpr void assign_from_extent(const T &pair) noexcept
Sets the width and height from a width-height pair.
Definition rect.hpp:220