VIPRA Documentation
Loading...
Searching...
No Matches
rectangle.hpp
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <numbers>
6#include <random>
7
8#include "vipra/geometry/definitions.hpp"
9#include "vipra/geometry/f3d.hpp"
10#include "vipra/geometry/line.hpp"
11#include "vipra/random/random.hpp"
12#include "vipra/types/float.hpp"
13
14namespace VIPRA::Geometry {
15
16class Polygon;
17class Circle;
18class Triangle;
19
20class Rectangle {
21 public:
22 VIPRA_POLY_FUNC auto is_point_inside(f3d point) const noexcept -> bool;
23 [[nodiscard]] auto random_point(Random::Engine& engine) const noexcept -> f3d;
24 VIPRA_POLY_FUNC auto sides() const noexcept -> std::array<Line, 4>;
25 VIPRA_POLY_FUNC auto rotation() const noexcept -> f_pnt;
26
27 VIPRA_POLY_FUNC auto center() const noexcept -> f3d const& { return _center; }
28 VIPRA_POLY_FUNC auto area() const noexcept -> f_pnt { return _area; }
29 VIPRA_POLY_FUNC auto width() const noexcept -> f_pnt { return _width; }
30 VIPRA_POLY_FUNC auto height() const noexcept -> f_pnt { return _height; }
31 VIPRA_POLY_FUNC auto points() const noexcept -> std::array<f3d, 4> const&
32 {
33 return _points;
34 }
35
36 private:
37 std::array<f3d, 4> _points;
38 f3d _center;
39 f_pnt _area{};
40 f_pnt _width{};
41 f_pnt _height{};
42
43 constexpr void calc_dims()
44 {
45 _width = _points[0].distance_to(_points[3]);
46 _height = _points[0].distance_to(_points[1]);
47 }
48
49 public:
50 constexpr explicit Rectangle(f3d point1, f3d point2, f3d point3, f3d point4)
51 : _points({point1, point2, point3, point4})
52 {
53 calc_dims();
54 _area = _height * _width;
55 }
56 constexpr explicit Rectangle(std::array<f3d, 4> const& points) : _points(points)
57 {
58 calc_dims();
59 _area = _height * _width;
60 }
61 constexpr explicit Rectangle(std::array<f3d, 4>&& points) : _points(points)
62 {
63 calc_dims();
64 _area = _height * _width;
65 }
66 constexpr explicit Rectangle(std::vector<Line> const& lines)
67 {
68 std::transform(lines.begin(), lines.end(), _points.begin(),
69 [](Line const& line) { return line.start; });
70 calc_dims();
71 _area = _height * _width;
72 }
73
74 constexpr explicit Rectangle(std::vector<Line>&& lines)
75 {
76 std::transform(lines.begin(), lines.end(), _points.begin(),
77 [](Line const& line) { return line.start; });
78 calc_dims();
79 _area = _height * _width;
80 }
81
82 constexpr explicit Rectangle(std::array<Line, 4> const& lines)
83 {
84 std::transform(lines.begin(), lines.end(), _points.begin(),
85 [](Line const& line) { return line.start; });
86 calc_dims();
87 _area = _height * _width;
88 }
89
90 constexpr explicit Rectangle(std::array<Line, 4>&& lines)
91 {
92 std::transform(lines.begin(), lines.end(), _points.begin(),
93 [](Line const& line) { return line.start; });
94 calc_dims();
95 _area = _height * _width;
96 }
97 constexpr Rectangle(VIPRA::f3d const& center, VIPRA::f3d const& dimensions,
98 VIPRA::f_pnt rotation);
99
100 ~Rectangle() = default;
101 constexpr Rectangle() = default;
102 constexpr Rectangle(Rectangle const&) = default;
103 constexpr auto operator=(Rectangle const&) -> Rectangle& = default;
104 constexpr Rectangle(Rectangle&&) noexcept = default;
105 constexpr auto operator=(Rectangle&&) noexcept -> Rectangle& = default;
106};
107
108VIPRA_POLY_FUNC auto Rectangle::is_point_inside(f3d point) const noexcept -> bool
109{
110 // NOLINTBEGIN(readability-identifier-length)
111 const f3d ab = _points[0] - _points[1];
112 const f3d am = _points[0] - point;
113 const f3d bc = _points[1] - _points[2];
114 const f3d bm = _points[1] - point;
115 const f_pnt dotABAM = ab.dot(am);
116 const f_pnt dotABAB = ab.dot(ab);
117 const f_pnt dotBCBM = bc.dot(bm);
118 const f_pnt dotBCBC = bc.dot(bc);
119 return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
120 // NOLINTEND(readability-identifier-length)
121}
122
123inline auto Rectangle::random_point(Random::Engine& engine) const noexcept -> f3d
124{
125 // TODO(rolland): implement a better method for this
126 f3d min{std::numeric_limits<VIPRA::f_pnt>::max(),
127 std::numeric_limits<VIPRA::f_pnt>::max()};
128 f3d max{std::numeric_limits<VIPRA::f_pnt>::min(),
129 std::numeric_limits<VIPRA::f_pnt>::min()};
130 for ( auto const& point : _points ) {
131 max.x = std::max(max.x, point.x);
132 max.y = std::max(max.y, point.y);
133 min.x = std::min(min.x, point.x);
134 min.y = std::min(min.y, point.y);
135 }
136
137 std::uniform_real_distribution<VIPRA::f_pnt> xDist{min.x, max.x};
138 std::uniform_real_distribution<VIPRA::f_pnt> yDist{min.y, max.y};
139
140 f3d point;
141
142 do {
143 point.x = xDist(engine);
144 point.y = yDist(engine);
145 } while ( ! is_point_inside(point) );
146 return point;
147}
148
149VIPRA_POLY_FUNC auto Rectangle::sides() const noexcept -> std::array<Line, 4>
150{
151 std::array<Line, 4> lines;
152 for ( size_t i = 0; i < 4; ++i ) {
153 lines[i] = Line{_points[i], _points[i + 1]};
154 }
155 lines.back() = Line{_points.back(), _points.front()};
156 return lines;
157}
158
159VIPRA_POLY_FUNC auto Rectangle::rotation() const noexcept -> f_pnt
160{
161 constexpr f_pnt HALF = 180.0;
162 constexpr f_pnt FULL = 360.0;
163
164 const f_pnt xDif = _points[0].x - _points[2].x;
165 const f_pnt yDif = _points[0].y - _points[2].y;
166
167 f_pnt rotation = std::atan(xDif / yDif) * HALF / std::numbers::pi;
168 if ( yDif < 0 ) {
169 rotation += HALF;
170 }
171 else if ( xDif < 0 ) {
172 rotation += FULL;
173 }
174
175 return rotation;
176}
177
178constexpr Rectangle::Rectangle(VIPRA::f3d const& center, VIPRA::f3d const& dimensions,
179 VIPRA::f_pnt rotation)
180 : _center(center)
181{
182 const VIPRA::f3d point1 = VIPRA::f3d{center.x + ((dimensions.x / 2) * cos(rotation)) -
183 ((dimensions.y / 2) * sin(rotation)),
184 center.y + ((dimensions.x / 2) * sin(rotation)) +
185 ((dimensions.y / 2) * cos(rotation))};
186 const VIPRA::f3d point2 = VIPRA::f3d{center.x - ((dimensions.x / 2) * cos(rotation)) -
187 ((dimensions.y / 2) * sin(rotation)),
188 center.y - ((dimensions.x / 2) * sin(rotation)) +
189 ((dimensions.y / 2) * cos(rotation))};
190 const VIPRA::f3d point3 = VIPRA::f3d{center.x - ((dimensions.x / 2) * cos(rotation)) +
191 ((dimensions.y / 2) * sin(rotation)),
192 center.y - ((dimensions.x / 2) * sin(rotation)) -
193 ((dimensions.y / 2) * cos(rotation))};
194 const VIPRA::f3d point4 = VIPRA::f3d{center.x + ((dimensions.x / 2) * cos(rotation)) +
195 ((dimensions.y / 2) * sin(rotation)),
196 center.y + ((dimensions.x / 2) * sin(rotation)) -
197 ((dimensions.y / 2) * cos(rotation))};
198
199 _points = {point1, point2, point3, point4};
200 calc_dims();
201 _area = _height * _width;
202}
203
204} // namespace VIPRA::Geometry
Definition circle.hpp:9
Definition polygon.hpp:18
Definition triangle.hpp:17
Psuedo Random number engine.
Definition random.hpp:22
Definition line.hpp:11
Definition f3d.hpp:27
F3D_FUNC auto dot(f3d const &other) const noexcept -> VIPRA::f_pnt
Returns the dot product between two f3ds.
Definition f3d.hpp:261