source: trunk/src/core/random.cc @ 437

Last change on this file since 437 was 402, checked in by epyon, 10 years ago
  • cleanups of clang warnings (gotta love them all)
  • only nv-core for now (this will take a while for the whole source)
  • mainly C++ casts instead of C-style casts, but also a few bugs fixed!
File size: 9.4 KB
Line 
1// Copyright (C) 2012-2014 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/core/random.hh"
8#include "nv/core/time.hh"
9#include <random>
10
11using namespace nv;
12
13random::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
19random::seed_type random::randomize()
20{
21        std::mt19937& rng = *( reinterpret_cast< std::mt19937* >( m_data ) );
22        seed_type seed = randomized_seed();
23        rng.seed( seed );
24        return seed;
25}
26
27void random::set_seed( random::seed_type seed /*= 0 */ )
28{
29        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
30        rng.seed( seed == 0 ? randomized_seed() : seed );
31}
32
33nv::random& random::get()
34{
35        static random default_rng;
36        return default_rng;
37}
38
39random::result_type random::rand()
40{
41        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
42        return rng();
43}
44
45sint32 random::srand( sint32 val )
46{
47        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
48        std::uniform_int_distribution<sint32> dist( 0, val - 1 );
49        return dist( rng );
50}
51
52uint32 random::urand( uint32 val )
53{
54        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
55        std::uniform_int_distribution<uint32> dist( 0, val - 1 );
56        return dist( rng );
57}
58
59f32 random::frand( f32 val )
60{
61        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
62        std::uniform_real_distribution<f32> dist( 0, val );
63        return dist( rng );
64}
65
66sint32 random::srange( sint32 min, sint32 max )
67{
68        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
69        std::uniform_int_distribution<sint32> dist( min, max );
70        return dist( rng );
71}
72
73uint32 random::urange( uint32 min, uint32 max )
74{
75        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
76        std::uniform_int_distribution<uint32> dist( min, max );
77        return dist( rng );
78}
79
80f32 random::frange( f32 min, f32 max )
81{
82        std::mt19937& rng = *( reinterpret_cast<std::mt19937*>( m_data ) );
83        std::uniform_real_distribution<f32> dist( min, max );
84        return dist( rng );
85}
86
87uint32 random::dice( uint32 count, uint32 sides )
88{
89        std::mt19937& rng = *( reinterpret_cast<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
99random::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
106nv::vec2 nv::random::precise_unit_vec2()
107{
108        std::mt19937& rng = *( reinterpret_cast<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
114nv::vec3 nv::random::precise_unit_vec3()
115{
116        std::mt19937& rng = *( reinterpret_cast<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
129nv::vec2 nv::random::fast_disk_point()
130{
131        std::mt19937& rng = *( reinterpret_cast<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
140nv::vec2 nv::random::precise_disk_point()
141{
142        std::mt19937& rng = *( reinterpret_cast<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
150nv::vec3 nv::random::fast_sphere_point()
151{
152        std::mt19937& rng = *( reinterpret_cast<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
168nv::vec3 nv::random::precise_sphere_point()
169{
170        std::mt19937& rng = *( reinterpret_cast<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
185nv::vec2 nv::random::precise_ellipse_point( const vec2& radii )
186{
187        std::mt19937& rng = *( reinterpret_cast<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
204nv::vec3 nv::random::precise_ellipsoid_point( const vec3& radii )
205{
206        std::mt19937& rng = *( reinterpret_cast<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
225nv::vec2 nv::random::fast_hollow_disk_point( float iradius, float oradius )
226{
227        std::mt19937& rng = *( reinterpret_cast<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
234nv::vec2 nv::random::precise_hollow_disk_point( float iradius, float oradius )
235{
236        return fast_hollow_disk_point( iradius, oradius );
237}
238
239nv::vec3 nv::random::fast_hollow_sphere_point( float iradius, float oradius )
240{
241        std::mt19937& rng = *( reinterpret_cast<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
248nv::vec3 nv::random::precise_hollow_sphere_point( float iradius, float oradius )
249{
250        return fast_hollow_sphere_point( iradius, oradius );
251}
252
253
254nv::vec2 nv::random::fast_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
255{
256        std::mt19937& rng = *( reinterpret_cast<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
270nv::vec2 nv::random::precise_hollow_ellipse_point( const vec2& iradii, const vec2& oradii )
271{
272        return fast_hollow_ellipse_point( iradii, oradii );
273}
274
275nv::vec3 nv::random::fast_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
276{
277        std::mt19937& rng = *( reinterpret_cast<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
297nv::vec3 nv::random::precise_hollow_ellipsoid_point( const vec3& iradii, const vec3& oradii )
298{
299        return fast_hollow_ellipsoid_point( iradii, oradii );
300}
301
Note: See TracBrowser for help on using the repository browser.