1 | // Copyright (C) 2012-2014 ChaosForge Ltd
|
---|
2 | // http://chaosforge.org/
|
---|
3 | //
|
---|
4 | // This file is part of NV Libraries.
|
---|
5 | // For conditions of distribution and use, see copyright notice in nv.hh
|
---|
6 |
|
---|
7 | #include "nv/core/random.hh"
|
---|
8 | #include "nv/core/time.hh"
|
---|
9 | #include <random>
|
---|
10 |
|
---|
11 | using namespace nv;
|
---|
12 |
|
---|
13 | random::random( random::seed_type seed /*= 0 */ )
|
---|
14 | {
|
---|
15 | static_assert( sizeof( std::mt19937 ) < sizeof( random::m_data ), "No room for mersenne twister!" );
|
---|
16 | new (m_data)std::mt19937( seed == 0 ? randomized_seed() : seed );
|
---|
17 | }
|
---|
18 |
|
---|
19 | random::seed_type random::randomize()
|
---|
20 | {
|
---|
21 | std::mt19937& rng = *(( std::mt19937* )m_data);
|
---|
22 | seed_type seed = randomized_seed();
|
---|
23 | rng.seed( seed );
|
---|
24 | return seed;
|
---|
25 | }
|
---|
26 |
|
---|
27 | void random::set_seed( random::seed_type seed /*= 0 */ )
|
---|
28 | {
|
---|
29 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
30 | rng.seed( seed == 0 ? randomized_seed() : seed );
|
---|
31 | }
|
---|
32 |
|
---|
33 | nv::random& random::get()
|
---|
34 | {
|
---|
35 | static random default_rng;
|
---|
36 | return default_rng;
|
---|
37 | }
|
---|
38 |
|
---|
39 | random::result_type random::rand()
|
---|
40 | {
|
---|
41 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
42 | return rng();
|
---|
43 | }
|
---|
44 |
|
---|
45 | sint32 random::srand( sint32 val )
|
---|
46 | {
|
---|
47 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
48 | std::uniform_int_distribution<sint32> dist( 0, val - 1 );
|
---|
49 | return dist( rng );
|
---|
50 | }
|
---|
51 |
|
---|
52 | uint32 random::urand( uint32 val )
|
---|
53 | {
|
---|
54 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
55 | std::uniform_int_distribution<uint32> dist( 0, val - 1 );
|
---|
56 | return dist( rng );
|
---|
57 | }
|
---|
58 |
|
---|
59 | f32 random::frand( f32 val )
|
---|
60 | {
|
---|
61 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
62 | std::uniform_real_distribution<f32> dist( 0, val );
|
---|
63 | return dist( rng );
|
---|
64 | }
|
---|
65 |
|
---|
66 | sint32 random::srange( sint32 min, sint32 max )
|
---|
67 | {
|
---|
68 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
69 | std::uniform_int_distribution<sint32> dist( min, max );
|
---|
70 | return dist( rng );
|
---|
71 | }
|
---|
72 |
|
---|
73 | uint32 random::urange( uint32 min, uint32 max )
|
---|
74 | {
|
---|
75 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
76 | std::uniform_int_distribution<uint32> dist( min, max );
|
---|
77 | return dist( rng );
|
---|
78 | }
|
---|
79 |
|
---|
80 | f32 random::frange( f32 min, f32 max )
|
---|
81 | {
|
---|
82 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
83 | std::uniform_real_distribution<f32> dist( min, max );
|
---|
84 | return dist( rng );
|
---|
85 | }
|
---|
86 |
|
---|
87 | uint32 random::dice( uint32 count, uint32 sides )
|
---|
88 | {
|
---|
89 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
90 | std::uniform_int_distribution<uint32> dist( 1, sides );
|
---|
91 | uint32 result = 0;
|
---|
92 | while (count-- > 0)
|
---|
93 | {
|
---|
94 | result += dist( rng );
|
---|
95 | };
|
---|
96 | return result;
|
---|
97 | }
|
---|
98 |
|
---|
99 | random::seed_type random::randomized_seed()
|
---|
100 | {
|
---|
101 | // TODO: this seems off, as it might often seed the same, use general time
|
---|
102 | // instead
|
---|
103 | return narrow_cast< seed_type >( get_ticks() );
|
---|
104 | }
|
---|
105 |
|
---|
106 | nv::vec2 nv::random::precise_unit_vec2()
|
---|
107 | {
|
---|
108 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
109 | std::uniform_real_distribution<f32> dist( 0, glm::pi<float>() * 2.f );
|
---|
110 | float angle = dist( rng );
|
---|
111 | return vec2( glm::cos( angle ), glm::sin( angle ) );
|
---|
112 | }
|
---|
113 |
|
---|
114 | nv::vec3 nv::random::precise_unit_vec3()
|
---|
115 | {
|
---|
116 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
117 | std::uniform_real_distribution<f32> dist11( -1.0f, 1.0f );
|
---|
118 | std::uniform_real_distribution<f32> dist02pi( 0.0f, 2*glm::pi<float>() );
|
---|
119 | float cos_theta = dist11( rng );
|
---|
120 | float sin_theta = glm::sqrt( 1.0f - cos_theta * cos_theta );
|
---|
121 | float phi = dist02pi( rng );
|
---|
122 | return vec3(
|
---|
123 | sin_theta * glm::sin(phi),
|
---|
124 | sin_theta * glm::cos(phi),
|
---|
125 | cos_theta
|
---|
126 | );
|
---|
127 | }
|
---|
128 |
|
---|
129 | nv::vec2 nv::random::fast_disk_point()
|
---|
130 | {
|
---|
131 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
132 | std::uniform_real_distribution<f32> dist( 0.0f, 1.0f );
|
---|
133 | float r1 = dist( rng );
|
---|
134 | float r2 = dist( rng );
|
---|
135 | if ( r1 > r2 ) std::swap( r1, r2 );
|
---|
136 | float rf = 2*glm::pi<float>()*(r1/r2);
|
---|
137 | return vec2( r2*glm::cos( rf ), r2*glm::sin( rf ) );
|
---|
138 | }
|
---|
139 |
|
---|
140 | nv::vec2 nv::random::precise_disk_point()
|
---|
141 | {
|
---|
142 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
143 | std::uniform_real_distribution<f32> unit( 0.0f, 1.0f );
|
---|
144 | std::uniform_real_distribution<f32> angle( 0.0f, glm::pi<float>() );
|
---|
145 | float r = glm::sqrt( unit( rng ) );
|
---|
146 | float rangle = angle( rng );
|
---|
147 | return vec2( r*glm::cos( rangle ), r*glm::sin( rangle ) );
|
---|
148 | }
|
---|
149 |
|
---|
150 | nv::vec3 nv::random::fast_sphere_point()
|
---|
151 | {
|
---|
152 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
153 | std::uniform_real_distribution<f32> dist01( 0.0f, 1.0f );
|
---|
154 | std::uniform_real_distribution<f32> dist11( -1.0f, 1.0f );
|
---|
155 | std::uniform_real_distribution<f32> dist02pi( 0.0f, 2*glm::pi<float>() );
|
---|
156 | float rad = dist01( rng );
|
---|
157 | float pi = glm::pi<float>();
|
---|
158 | float phi = glm::asin( dist11( rng ) ) + pi*.5f;
|
---|
159 | float theta = dist02pi( rng );
|
---|
160 | float sin_phi = glm::sin( phi );
|
---|
161 | return vec3(
|
---|
162 | rad * glm::cos(theta) * sin_phi,
|
---|
163 | rad * glm::sin(theta) * sin_phi,
|
---|
164 | rad * glm::cos(phi)
|
---|
165 | );
|
---|
166 | }
|
---|
167 |
|
---|
168 | nv::vec3 nv::random::precise_sphere_point()
|
---|
169 | {
|
---|
170 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
171 | std::uniform_real_distribution<f32> dist01( 0.0f, 1.0f );
|
---|
172 | std::uniform_real_distribution<f32> dist11( -1.0f, 1.0f );
|
---|
173 | std::uniform_real_distribution<f32> dist02pi( 0.0f, 2*glm::pi<float>() );
|
---|
174 | float radius = std::pow( dist01( rng ), 1.f/3.f );
|
---|
175 | float cos_theta = dist11( rng );
|
---|
176 | float sin_theta = glm::sqrt( 1.0f - cos_theta * cos_theta );
|
---|
177 | float phi = dist02pi( rng );
|
---|
178 | return vec3(
|
---|
179 | radius * sin_theta * glm::sin(phi),
|
---|
180 | radius * sin_theta * glm::cos(phi),
|
---|
181 | radius * cos_theta
|
---|
182 | );
|
---|
183 | }
|
---|
184 |
|
---|
185 | nv::vec2 nv::random::precise_ellipse_point( const vec2& radii )
|
---|
186 | {
|
---|
187 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
188 | std::uniform_real_distribution<f32> distx( -radii.x, radii.x );
|
---|
189 | std::uniform_real_distribution<f32> disty( -radii.y, radii.y );
|
---|
190 | vec2 inv_radii = 1.f / radii;
|
---|
191 | vec2 inv_radii2 = inv_radii * inv_radii;
|
---|
192 | for ( uint32 i = 0; i < 12; ++i )
|
---|
193 | {
|
---|
194 | float x = distx( rng );
|
---|
195 | float y = disty( rng );
|
---|
196 | if ( x * x * inv_radii2.x + y * y * inv_radii2.y <= 1.f )
|
---|
197 | {
|
---|
198 | return vec2( x, y );
|
---|
199 | }
|
---|
200 | }
|
---|
201 | return fast_disk_point() * radii;
|
---|
202 | }
|
---|
203 |
|
---|
204 | nv::vec3 nv::random::precise_ellipsoid_point( const vec3& radii )
|
---|
205 | {
|
---|
206 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
207 | std::uniform_real_distribution<f32> distx( -radii.x, radii.x );
|
---|
208 | std::uniform_real_distribution<f32> disty( -radii.y, radii.y );
|
---|
209 | std::uniform_real_distribution<f32> distz( -radii.z, radii.z );
|
---|
210 | vec3 inv_radii = 1.f / radii;
|
---|
211 | vec3 inv_radii2 = inv_radii * inv_radii;
|
---|
212 | for ( uint32 i = 0; i < 12; ++i )
|
---|
213 | {
|
---|
214 | float x = distx( rng );
|
---|
215 | float y = disty( rng );
|
---|
216 | float z = distz( rng );
|
---|
217 | if ( x * x * inv_radii2.x + y * y * inv_radii2.y + z * z * inv_radii2.z <= 1.f )
|
---|
218 | {
|
---|
219 | return vec3( x, y, z );
|
---|
220 | }
|
---|
221 | }
|
---|
222 | return fast_sphere_point() * radii;
|
---|
223 | }
|
---|
224 |
|
---|
225 | nv::vec2 nv::random::fast_hollow_disk_point( float iradius, float oradius )
|
---|
226 | {
|
---|
227 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
228 | float idist2 = iradius * iradius;
|
---|
229 | float odist2 = oradius * oradius;
|
---|
230 | float rdist = glm::sqrt( std::uniform_real_distribution<f32>( idist2, odist2 )( rng ) );
|
---|
231 | return rdist * precise_unit_vec2();
|
---|
232 | }
|
---|
233 |
|
---|
234 | nv::vec2 nv::random::precise_hollow_disk_point( float iradius, float oradius )
|
---|
235 | {
|
---|
236 | return fast_hollow_disk_point( iradius, oradius );
|
---|
237 | }
|
---|
238 |
|
---|
239 | nv::vec3 nv::random::fast_hollow_sphere_point( float iradius, float oradius )
|
---|
240 | {
|
---|
241 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
242 | float idist3 = iradius * iradius * iradius;
|
---|
243 | float odist3 = oradius * oradius * oradius;
|
---|
244 | float rdist = std::pow( std::uniform_real_distribution<f32>( idist3, odist3 )( rng ), 1.f/3.f );
|
---|
245 | return rdist * precise_unit_vec3();
|
---|
246 | }
|
---|
247 |
|
---|
248 | nv::vec3 nv::random::precise_hollow_sphere_point( float iradius, float oradius )
|
---|
249 | {
|
---|
250 | return fast_hollow_sphere_point( iradius, oradius );
|
---|
251 | }
|
---|
252 |
|
---|
253 |
|
---|
254 | nv::vec2 nv::random::fast_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
|
---|
255 | {
|
---|
256 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
257 | vec2 iradii2 = iradii * iradii;
|
---|
258 | vec2 opoint = ellipse_edge( oradii );
|
---|
259 | vec2 opoint2 = opoint * opoint;
|
---|
260 | vec2 odir = glm::normalize( opoint );
|
---|
261 | float odist2 = opoint2.x + opoint2.y;
|
---|
262 |
|
---|
263 | float low = iradii2.y * opoint2.x + iradii2.x * opoint2.y;
|
---|
264 | float idist2 = ((iradii2.x * iradii2.y) / low ) * odist2;
|
---|
265 |
|
---|
266 | float rdist = glm::sqrt( std::uniform_real_distribution<f32>( idist2, odist2 )( rng ) );
|
---|
267 | return odir * rdist;
|
---|
268 | }
|
---|
269 |
|
---|
270 | nv::vec2 nv::random::precise_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
|
---|
271 | {
|
---|
272 | return fast_hollow_ellipse_point( iradii, oradii );
|
---|
273 | }
|
---|
274 |
|
---|
275 | nv::vec3 nv::random::fast_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
|
---|
276 | {
|
---|
277 | std::mt19937& rng = *( ( std::mt19937* )m_data );
|
---|
278 | vec3 iradii2 = iradii * iradii;
|
---|
279 | vec3 opoint = ellipsoid_edge( oradii );
|
---|
280 | vec3 opoint2 = opoint * opoint;
|
---|
281 | vec3 odir = glm::normalize( opoint );
|
---|
282 | float odist2 = opoint2.x + opoint2.y + opoint2.z;
|
---|
283 |
|
---|
284 | float low =
|
---|
285 | iradii2.y * iradii2.z * opoint2.x +
|
---|
286 | iradii2.x * iradii2.z * opoint2.y +
|
---|
287 | iradii2.x * iradii2.y * opoint2.z;
|
---|
288 | float idist2 = ((iradii2.x * iradii2.y * iradii2.z) / low ) * odist2;
|
---|
289 |
|
---|
290 | float odist3 = odist2 * glm::sqrt( odist2 );
|
---|
291 | float idist3 = idist2 * glm::sqrt( idist2 );
|
---|
292 |
|
---|
293 | float rdist = std::pow( std::uniform_real_distribution<f32>( idist3, odist3 )( rng ), 1.f/3.f );
|
---|
294 | return odir * rdist;
|
---|
295 | }
|
---|
296 |
|
---|
297 | nv::vec3 nv::random::precise_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
|
---|
298 | {
|
---|
299 | return fast_hollow_ellipsoid_point( iradii, oradii );
|
---|
300 | }
|
---|
301 |
|
---|