header_utils
Loading...
Searching...
No Matches
random_geom.h
1
4
5#pragma once
6
7#include "random.h"
8#include "rec2.h"
9#include "geometry/ellipse.h"
10#include "geometry/polygon.h"
11#include "geometry/shape_concepts.h"
12#define GLM_ENABLE_EXPERIMENTAL 1
13#include <glm/ext/scalar_constants.hpp>
14#include <glm/gtx/rotate_vector.hpp>
15
16namespace ghassanpl::random
17{
21
22 template <std::floating_point T = float, typename RANDOM = std::default_random_engine>
23 [[nodiscard]] T radians(RANDOM& rng = ::ghassanpl::random::default_random_engine)
24 {
25 static std::uniform_real_distribution<T> dist{ T{}, glm::pi<T>() * 2 };
26 return dist(rng);
27 }
28
29 template <std::floating_point T = float, typename RANDOM = std::default_random_engine>
30 [[nodiscard]] T degrees(RANDOM& rng = ::ghassanpl::random::default_random_engine)
31 {
32 static std::uniform_real_distribution<T> dist{ T{}, T{360} };
33 return dist(rng);
34 }
35
36 template <std::floating_point T = float, typename RANDOM = std::default_random_engine>
37 [[nodiscard]] glm::tvec2<T> unit_vector(RANDOM& rng = ::ghassanpl::random::default_random_engine)
38 {
39 return glm::rotate(glm::tvec2<T>{ T{ 1 }, T{ 0 } }, radians<T>(rng));
40 }
41
42 template <typename T, typename RANDOM = std::default_random_engine>
43 [[nodiscard]] glm::tvec2<T> point_in(trec2<T> const& rect, RANDOM& rng = ::ghassanpl::random::default_random_engine)
44 {
45 return { in_range(rect.p1.x, rect.p2.x, rng), in_range(rect.p1.y, rect.p2.y, rng) };
46 }
47
48 template <typename T, typename RANDOM = std::default_random_engine>
49 [[nodiscard]] glm::tvec2<T> point_in(glm::tvec2<T> const& max, RANDOM& rng = ::ghassanpl::random::default_random_engine)
50 {
51 return { in_range(T{}, max.x, rng), in_range(T{}, max.y, rng) };
52 }
53
55 template <typename T, typename RANDOM = std::default_random_engine>
56 [[nodiscard]] glm::tvec2<T> point_in(geometry::tellipse<T> const& el, RANDOM& rng = ::ghassanpl::random::default_random_engine)
57 {
58 const auto phi = between(T{}, glm::two_pi<T>(), rng);
59 const auto p = glm::tvec2<T>{ cos(phi), sin(phi) } * glm::sqrt(percentage<T>(rng)) * el.radii * T(0.5);
60 return p + el.center;
61 }
62
63 template <typename T, typename RANDOM = std::default_random_engine>
64 [[nodiscard]] glm::tvec2<T> point_in(geometry::ttriangle<T> const& tr, RANDOM& rng = ::ghassanpl::random::default_random_engine)
65 {
66 const auto r1 = glm::sqrt(percentage<T>(rng));
67 const auto r2 = percentage<T>(rng);
68
69 return (tr.a * (T(1) - r1) + tr.b * (r1 * (T(1) - r2)) + tr.c * (r2 * r1));
70 }
71
72 template <typename T, typename RANDOM = std::default_random_engine>
73 [[nodiscard]] glm::tvec2<T> point_in(geometry::immutable::tpolygon<T> const& poly, RANDOM& rng = ::ghassanpl::random::default_random_engine)
74 {
75 if (poly.triangles().empty()) return {};
76
77 auto r = between(T{}, poly.calculate_area());
78 size_t i = 0;
79 while (r > 0.0)
80 {
81 if (!poly.has_triangle(i))
82 return {};
83
84 r -= poly.triangle_area(i);
85 if (r <= 0.0)
86 break;
87 i++;
88 }
89
90 return point_in(poly.triangle(i), rng);
91 }
92
94 template <typename T, geometry::shape<T> S, typename RANDOM = std::default_random_engine>
95 [[nodiscard]] glm::tvec2<T> point_on(S const& shape, RANDOM& rng = ::ghassanpl::random::default_random_engine)
96 {
97 return shape.edge_point_alpha(percentage(rng));
98 }
99
100 // TODO: in(circle), in(poly)?, on(rect), on(circle), on(arc)
101 /*
102 template <typename T>
103 auto RandomNotIn(ghassanpl::trec2<T> const& verboten, ghassanpl::trec2<T> const& bounds)
104 {
106 const std::array<ghassanpl::trec2<T>, 4> surrounding = {
107 ghassanpl::trec2<T>{ bounds.p1.x, bounds.p1.y, bounds.p2.x, verboten.p1.y },
108 ghassanpl::trec2<T>{ bounds.p1.x, verboten.p2.y, bounds.p2.x, bounds.p2.y },
109 ghassanpl::trec2<T>{ bounds.p1.x, bounds.p1.y, verboten.p1.x, bounds.p2.y },
110 ghassanpl::trec2<T>{ verboten.p2.x, bounds.p1.y, bounds.p2.x, bounds.p2.y },
111 };
112 const std::array<T, 4> areas = {
113 surrounding[0].calculate_area(),
114 surrounding[1].calculate_area(),
115 surrounding[2].calculate_area(),
116 surrounding[3].calculate_area()
117 };
118 const int total_area = areas[0] + areas[1] + areas[2] + areas[3];
119 const int rand_pos = RandomIn(total_area);
120 if (rand_pos < areas[0]) return Random(surrounding[0]);
121 if (rand_pos < areas[0] + areas[1]) return Random(surrounding[1]);
122 if (rand_pos < areas[0] + areas[1] + areas[2]) return Random(surrounding[2]);
123 return Random(surrounding[3]);
124 }
125 */
126
127 template <typename RANDOM = std::default_random_engine>
128 [[nodiscard]] glm::ivec2 neighbor(RANDOM& rng = ::ghassanpl::random::default_random_engine)
129 {
130 static std::uniform_int_distribution<typename RANDOM::result_type> dist{ 0, 3 };
131 switch (dist(rng))
132 {
133 case 0: return { 1.0f, 0.0f };
134 case 1: return { 0.0f, 1.0f };
135 case 2: return { -1.0f, 0.0f };
136 case 3: return { 0.0f, -1.0f };
137 }
138 return {};
139 }
140
141 template <typename RANDOM = std::default_random_engine>
142 [[nodiscard]] glm::ivec2 diagonal_neighbor(RANDOM& rng = ::ghassanpl::random::default_random_engine)
143 {
144 static std::uniform_int_distribution<typename RANDOM::result_type> dist{ 0, 3 };
145 switch (dist(rng))
146 {
147 case 0: return { 1.0f, 1.0f };
148 case 1: return { -1.0f, 1.0f };
149 case 2: return { -1.0f, -1.0f };
150 case 3: return { 1.0f, -1.0f };
151 }
152 return {};
153 }
154
155 template <typename RANDOM = std::default_random_engine>
156 [[nodiscard]] glm::ivec2 surrounding(RANDOM& rng = ::ghassanpl::random::default_random_engine)
157 {
158 static std::uniform_int_distribution<typename RANDOM::result_type> dist{ 0, 7 };
159 switch (dist(rng))
160 {
161 case 0: return { 1.0f, 0.0f };
162 case 1: return { 0.0f, 1.0f };
163 case 2: return { -1.0f, 0.0f };
164 case 3: return { 0.0f, -1.0f };
165 case 4: return { 1.0f, 1.0f };
166 case 5: return { -1.0f, 1.0f };
167 case 6: return { -1.0f, -1.0f };
168 case 7: return { 1.0f, -1.0f };
169 }
170 return {};
171 }
172
173 // TODO: Should we move the below to random_seq?
174
176 template <std::floating_point T = float>
177 [[nodiscard]] constexpr glm::tvec2<T> halton_sequence_2d(size_t index, size_t base_x = 2, size_t base_y = 3)
178 {
179 return { halton_sequence<T>(index, base_x), halton_sequence<T>(index, base_y) };
180 }
181
183
184}
constexpr glm::tvec2< T > halton_sequence_2d(size_t index, size_t base_x=2, size_t base_y=3)
Returns the nth quasi-random vector in the [0, 1]^2 space.
glm::tvec2< T > point_on(S const &shape, RANDOM &rng=::ghassanpl::random::default_random_engine)
Returns a random point on the edge of the shape.
Definition random_geom.h:95
std::default_random_engine default_random_engine
A thread-local random engine used by default by all random functions.
Definition random.h:58
REAL percentage(RANDOM &rng=::ghassanpl::random::default_random_engine)
Returns a random value between 0 and 1 of the given floating-point type.
Definition random.h:70
auto index(T &cont, RANDOM &rng=::ghassanpl::random::default_random_engine)
Returns an index of a random element in cont.
Definition random.h:331
Represents a 2D, axis-aligned ellipse area_shape.
Definition ellipse.h:19