TeiaCareSDK  v0.1.0
TeiaCareSDK is a collection of reusable C++ components
Loading...
Searching...
No Matches
rectangle.hpp
1// Copyright 2024 TeiaCare
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <teiacare/sdk/geometry/line.hpp>
18#include <teiacare/sdk/geometry/point.hpp>
19#include <teiacare/sdk/geometry/size.hpp>
20#include <teiacare/sdk/math.hpp>
21
22#include <algorithm>
23#include <string>
24
25namespace tc::sdk
26{
27/*!
28 * \class rectangle
29 * \brief 2D rectangle specified by a position point (top-left corner) and a pair of width/height dimensions.
30 * \tparam T Underlying coordinates and dimensions type
31 *
32 */
33template <typename T>
35{
36public:
37 /*!
38 * \brief Default Constructor. Creates a default tc::sdk::rectangle instance.
39 */
40 constexpr rectangle() = default;
41
42 /*!
43 * \brief Copy Constructor. Copy a tc::sdk::rectangle instance into another one.
44 */
45 constexpr rectangle(const rectangle&) = default;
46
47 /*!
48 * \brief Move Constructor. Copy a tc::sdk::rectangle instance into another one.
49 */
50 constexpr rectangle(rectangle&&) = default;
51
52 /*!
53 * \brief Constructor. Creates tc::sdk::rectangle instance with given width and height dimensions.
54 * \param position the position of the rectangle (top-left corner).
55 * \param w the width of the rectangle.
56 * \param h the height of the rectangle.
57 */
58 constexpr explicit rectangle(tc::sdk::point<T> position, T w, T h) noexcept
59 : _position{position}
60 , _width{w}
61 , _height{h}
62 {
63 }
64
65 /*!
66 * \brief Constructor. Creates tc::sdk::rectangle instance with given width and height dimensions.
67 * \param x the x coordinate of the rectangle position (top-left corner).
68 * \param y the y coordinate of the rectangle position (top-left corner).
69 * \param w the width of the rectangle.
70 * \param h the height of the rectangle.
71 */
72 constexpr explicit rectangle(T x, T y, T w, T h) noexcept
73 : _position{x, y}
74 , _width{w}
75 , _height{h}
76 {
77 }
78
79 /*!
80 * \brief Assignment operator. Assign a tc::sdk::rectangle instance to another one.
81 */
82 rectangle& operator=(const rectangle&) = default;
83
84 /*!
85 * \brief Move assignment operator. Assign a tc::sdk::rectangle instance to another one.
86 */
88
89 /*!
90 * \brief Equality operator.
91 * \param other the rectangle to compare against.
92 * \return true if the two rectangles have the same dimensions and the same position.
93 */
94 constexpr inline bool operator==(const rectangle& other) const noexcept
95 {
96 return _position == other._position &&
97 _width == other._width &&
98 _height == other._height;
99 }
100
101 /*!
102 * \brief Inequality operator.
103 * \param other the rectangle to compare against.
104 * \return true if the two rectangles have the different dimensions or different position.
105 */
106 constexpr inline bool operator!=(const rectangle& other) const noexcept
107 {
108 return !operator==(other);
109 }
110
111 /*!
112 * \brief Check if the rectangle is the null.
113 * \return true if both width and height are zero or negative.
114 */
115 constexpr bool is_null() const noexcept
116 {
117 return _width <= 0 && _height <= 0;
118 }
119
120 /*!
121 * \brief Width dimension getter.
122 * \return Width dimension of the rectangle.
123 */
124 constexpr inline T width() const noexcept
125 {
126 return _width;
127 }
128
129 /*!
130 * \brief Height dimension getter.
131 * \return Height dimension of the rectangle.
132 */
133 constexpr inline T height() const noexcept
134 {
135 return _height;
136 }
137
138 /*!
139 * \brief Width coordinate setter. Set the width dimension of the rectangle.
140 */
141 inline void set_width(T width) noexcept
142 {
143 _width = width;
144 }
145
146 /*!
147 * \brief Height coordinate setter. Set the height dimension of the rectangle.
148 */
149 inline void set_height(T height) noexcept
150 {
151 _height = height;
152 }
153
154 /*!
155 * \brief Size setter.
156 * \return Set the size of the rectangle.
157 */
158 constexpr inline void set_size(T width, T height) noexcept
159 {
160 _width = width;
161 _height = height;
162 }
163
164 /*!
165 * \brief Set the rectangle position.
166 * \param position the new top left coordinate of the rectangle.
167 */
168 constexpr inline void set_position(tc::sdk::point<T> position) noexcept
169 {
170 _position = position;
171 }
172
173 /*!
174 * \brief Top left coordinate getter.
175 * \return Top left coordinate of the rectangle.
176 */
178 {
179 return tc::sdk::point<T>(_position);
180 }
181
182 /*!
183 * \brief Top right coordinate getter.
184 * \return Top right coordinate of the rectangle.
185 */
187 {
188 return tc::sdk::point<T>(_position.x() + _width, _position.y());
189 }
190
191 /*!
192 * \brief Bottom left coordinate getter.
193 * \return Bottom left coordinate of the rectangle.
194 */
196 {
197 return tc::sdk::point<T>(_position.x(), _position.y() + _height);
198 }
199
200 /*!
201 * \brief Bottom right coordinate getter.
202 * \return Bottom right coordinate of the rectangle.
203 */
205 {
206 return tc::sdk::point<T>(_position.x() + _width, _position.y() + _height);
207 }
208
209 /*!
210 * \brief Size getter.
211 * \return The size of the rectangle.
212 */
214 {
215 return tc::sdk::size<T>(_width, _height);
216 }
217
218 /*!
219 * \brief Area getter.
220 * \return The area of the rectangle.
221 */
222 constexpr inline T area() const noexcept
223 {
224 return _width * _height;
225 }
226
227 /*!
228 * \brief Center getter.
229 * \return The center coordinate of the rectangle.
230 */
232 {
233 return tc::sdk::point<double>(_position.x() + _width * 0.5, _position.y() + _height * 0.5);
234 }
235
236 /*!
237 * \brief Check if the given point is strictly contained within the current rectangle.
238 * \param point The point that is checked.
239 * \return true if the point is strictly contained in the current rectangle.
240 */
241 bool contains(tc::sdk::point<T> point) const noexcept
242 {
243 return point.x() > _position.x() &&
244 point.y() > _position.y() &&
245 point.x() < _position.x() + _width &&
246 point.y() < _position.y() + _height;
247 }
248
249 /*!
250 * \brief Check if the given rectangle is strictly contained within the current rectangle.
251 * \param other The rectangle that is checked.
252 * \return true if the other rectangle is strictly contained in the current rectangle.
253 */
255 {
256 return _position.x() < other._position.x() &&
257 _position.y() < other._position.y() &&
258 _position.x() + _width >= other._position.x() + other._width &&
259 _position.y() + _height >= other._position.y() + other._height;
260 }
261
262 /*!
263 * \brief Check if the given rectangle overlaps the current rectangle.
264 * \param other The rectangle to check the intersection with.
265 * \return true if this and the other rectangles are overlapped.
266 */
268 {
269 return _position.x() + _width > other._position.x() &&
270 _position.y() + _height > other._position.y() &&
271 _position.x() < other._position.x() + other._width &&
272 _position.y() < other._position.y() + other._height &&
273 !other.is_null() &&
274 !is_null();
275 }
276
277 /*!
278 * \brief Check if the given line pass through the current rectangle.
279 * \param line The line to check the intersection with.
280 * \return true if the given line intersects the current rectangle.
281 */
291
292 /** Returns the region that is the overlap between this and another rectangle.
293 If the two rectangles don't overlap, the rectangle returned will be empty.
294 */
296 {
297 if (is_null() || other.is_null())
298 return tc::sdk::rectangle<T>{};
299
300 auto intersection_x = tc::sdk::max(_position.x(), other._position.x());
301 auto intersection_y = tc::sdk::max(_position.y(), other._position.y());
302
303 auto intersection_width = tc::sdk::min(_position.x() + _width, other._position.x() + other._width) - intersection_x;
304 if (intersection_width < T())
305 return tc::sdk::rectangle<T>{};
306
307 auto intersection_height = tc::sdk::min(_position.y() + _height, other._position.y() + other._height) - intersection_y;
308 if (intersection_height < T())
309 return tc::sdk::rectangle<T>{};
310
313 }
314
315 /** Returns the smallest rectangle that contains both this one and the one passed-in.
316
317 If either this or the other rectangle are empty, they will not be counted as
318 part of the resulting region.
319 */
321 {
322 if (other.is_null())
323 return *this;
324
325 if (is_null())
326 return other;
327
328 auto union_x = tc::sdk::min(_position.x(), other._position.x());
329 auto union_y = tc::sdk::min(_position.y(), other._position.y());
330
331 auto union_width = tc::sdk::max(_position.x() + _width, other._position.x() + other._width) - union_x;
332 auto union_height = tc::sdk::max(_position.y() + _height, other._position.y() + other._height) - union_y;
333
336 }
337
338 /*!
339 * \brief Translate the rectangle by a given delta_x and delta_y offsets.
340 * \param delta_x the offset to be applied on the x direction
341 * \param delta_y the offset to be applied on the y direction
342 */
343 void translate(T delta_x, T delta_y) noexcept
344 {
345 _position.add_delta(delta_x, delta_y);
346 }
347
348 /*!
349 * \brief Create a copy of the rectangle translated by a given delta_x and delta_y offsets.
350 * \param delta_x the offset to be applied on the x direction
351 * \param delta_y the offset to be applied on the y direction
352 * \return a translated copy of the current rectangle
353 */
355 {
356 const auto translated_position = tc::sdk::point<T>(_position);
358 return tc::sdk::rectangle<T>(translated_position, _width, _height);
359 }
360
361 /*!
362 * \brief Calculate Intersection over Union (IoU) with another rectangle.
363 * \param other The rectangle to calculate IoU with.
364 * \return The IoU value as a ratio of the intersection area to the union area.
365 */
366 double calculate_iou(const tc::sdk::rectangle<T>& other) const noexcept
367 {
368 // Early exit for null rectangles
369 if (is_null() || other.is_null())
370 {
371 return 0.0;
372 }
373
375 if (intersection_rect.is_null())
376 {
377 return 0.0;
378 }
379
380 const auto intersection_area = intersection_rect.area();
381 const auto union_area = area() + other.area() - intersection_area;
382
383 // Avoid division by zero
384 if (union_area == T(0.0))
385 {
386 return 0.0;
387 }
388
389 return static_cast<double>(intersection_area) / static_cast<double>(union_area);
390 }
391
392 /*!
393 * \brief Transform this rectangle from input coordinate space back to output coordinate space.
394 * This method handles the inverse transformation of letterboxing/padding applied during scaling.
395 * \param input_width The width of the input coordinate space.
396 * \param input_height The height of the input coordinate space.
397 * \param output_width The width of the output coordinate space.
398 * \param output_height The height of the output coordinate space.
399 * \return A rectangle transformed back to output coordinates.
400 */
402 T input_width,
403 T input_height,
404 T output_width,
405 T output_height) const noexcept
406 {
407 // Input validation
408 if (output_width <= T{} || output_height <= T{} ||
409 input_width <= T{} || input_height <= T{} ||
410 is_null())
411 {
412 return tc::sdk::rectangle<T>{};
413 }
414
415 // Calculate scale ratios for width and height
416 const auto scale_width = static_cast<double>(input_width) / output_width;
417 const auto scale_height = static_cast<double>(input_height) / output_height;
418
419 // Use the smaller ratio to maintain aspect ratio (letterboxing)
420 const auto scale = tc::sdk::min(scale_width, scale_height);
421
422 // Calculate actual scaled dimensions of the output in input space
425
426 // Calculate padding offsets (where letterbox bars are added)
427 const auto x_padding_offset = (input_width - scaled_output_width) * 0.5;
429
430 // Get input box boundaries (using this rectangle)
431 const auto input_left = static_cast<double>(top_left().x());
432 const auto input_top = static_cast<double>(top_left().y());
433 const auto input_right = input_left + width();
434 const auto input_bottom = input_top + height();
435
436 // Remove padding and scale back to output coordinates
437 const auto inverse_scale = 1.0 / scale;
442
443 // Clamp to output boundaries
444 const auto clamped_left = std::clamp(static_cast<T>(output_left), T{}, output_width);
445 const auto clamped_right = std::clamp(static_cast<T>(output_right), T{}, output_width);
446 const auto clamped_top = std::clamp(static_cast<T>(output_top), T{}, output_height);
447 const auto clamped_bottom = std::clamp(static_cast<T>(output_bottom), T{}, output_height);
448
449 // Calculate final dimensions
450 const auto final_width = tc::sdk::max(T{}, clamped_right - clamped_left);
451 const auto final_height = tc::sdk::max(T{}, clamped_bottom - clamped_top);
452
453 // Create and return the transformed rectangle
455 }
456
457 /*!
458 * \brief Get the rectangle string representation
459 * \return String representation of the current rectangle.
460 */
461 constexpr std::string to_string() const
462 {
463 return std::string(_position.to_string() + " : (" + std::to_string(_width) + "x" + std::to_string(_height) + ")");
464 }
465
466 /*!
467 * \brief Output stream operator.
468 * \param stream the output stream to write into.
469 * \param r the rectangle object to stream.
470 * \return reference to the output stream operator, with the rectangle string representation written into it.
471 */
472 friend std::ostream& operator<<(std::ostream& stream, const rectangle& r)
473 {
474 return stream << r.to_string();
475 }
476
477private:
478 tc::sdk::point<T> _position{};
479 T _width{};
480 T _height{};
481};
482
483}
Thread safe, blocking queue.
2D line specified by a pair of start/end points.
Definition line.hpp:32
constexpr tc::sdk::point< T > start() const noexcept
Start point getter.
Definition line.hpp:122
constexpr tc::sdk::point< T > end() const noexcept
End point getter.
Definition line.hpp:131
bool intersects(tc::sdk::line< T > other) const noexcept
Check if the given line segments intersects the current instance.
Definition line.hpp:157
2D point specified by a pair of (x,y) coordinates.
Definition point.hpp:30
constexpr T x() const noexcept
X coordinate getter.
Definition point.hpp:101
constexpr T y() const noexcept
Y coordinate getter.
Definition point.hpp:110
2D rectangle specified by a position point (top-left corner) and a pair of width/height dimensions.
Definition rectangle.hpp:35
constexpr tc::sdk::size< T > size() const noexcept
Size getter.
friend std::ostream & operator<<(std::ostream &stream, const rectangle &r)
Output stream operator.
constexpr tc::sdk::point< T > bottom_right() const noexcept
Bottom right coordinate getter.
constexpr rectangle(const rectangle &)=default
Copy Constructor. Copy a tc::sdk::rectangle instance into another one.
constexpr void set_size(T width, T height) noexcept
Size setter.
constexpr T height() const noexcept
Height dimension getter.
bool contains(tc::sdk::rectangle< T > other) const noexcept
Check if the given rectangle is strictly contained within the current rectangle.
tc::sdk::rectangle< T > reshape(T input_width, T input_height, T output_width, T output_height) const noexcept
Transform this rectangle from input coordinate space back to output coordinate space....
tc::sdk::rectangle< T > get_union(tc::sdk::rectangle< T > other) const noexcept
constexpr T area() const noexcept
Area getter.
constexpr rectangle(T x, T y, T w, T h) noexcept
Constructor. Creates tc::sdk::rectangle instance with given width and height dimensions.
Definition rectangle.hpp:72
constexpr std::string to_string() const
Get the rectangle string representation.
constexpr bool is_null() const noexcept
Check if the rectangle is the null.
constexpr tc::sdk::point< T > bottom_left() const noexcept
Bottom left coordinate getter.
constexpr void set_position(tc::sdk::point< T > position) noexcept
Set the rectangle position.
tc::sdk::rectangle< T > translated(T delta_x, T delta_y) const noexcept
Create a copy of the rectangle translated by a given delta_x and delta_y offsets.
rectangle & operator=(const rectangle &)=default
Assignment operator. Assign a tc::sdk::rectangle instance to another one.
bool intersects(tc::sdk::line< T > line) const noexcept
Check if the given line pass through the current rectangle.
void set_width(T width) noexcept
Width coordinate setter. Set the width dimension of the rectangle.
double calculate_iou(const tc::sdk::rectangle< T > &other) const noexcept
Calculate Intersection over Union (IoU) with another rectangle.
bool contains(tc::sdk::point< T > point) const noexcept
Check if the given point is strictly contained within the current rectangle.
constexpr tc::sdk::point< double > center() const noexcept
Center getter.
constexpr bool operator==(const rectangle &other) const noexcept
Equality operator.
Definition rectangle.hpp:94
tc::sdk::rectangle< T > get_intersection(tc::sdk::rectangle< T > other) const noexcept
constexpr rectangle()=default
Default Constructor. Creates a default tc::sdk::rectangle instance.
constexpr rectangle(tc::sdk::point< T > position, T w, T h) noexcept
Constructor. Creates tc::sdk::rectangle instance with given width and height dimensions.
Definition rectangle.hpp:58
constexpr rectangle(rectangle &&)=default
Move Constructor. Copy a tc::sdk::rectangle instance into another one.
void translate(T delta_x, T delta_y) noexcept
Translate the rectangle by a given delta_x and delta_y offsets.
constexpr tc::sdk::point< T > top_right() const noexcept
Top right coordinate getter.
constexpr tc::sdk::point< T > top_left() const noexcept
Top left coordinate getter.
void set_height(T height) noexcept
Height coordinate setter. Set the height dimension of the rectangle.
bool intersects(tc::sdk::rectangle< T > other) const noexcept
Check if the given rectangle overlaps the current rectangle.
constexpr bool operator!=(const rectangle &other) const noexcept
Inequality operator.
constexpr T width() const noexcept
Width dimension getter.
rectangle & operator=(rectangle &&)=default
Move assignment operator. Assign a tc::sdk::rectangle instance to another one.