source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/RndGauss.h @ 2886

Revision 2886, 4.7 KB checked in by mattausch, 16 years ago (diff)

using gaussian distribution for sampling

Line 
1// ===================================================================
2// $Id:$
3//
4// rndgauss.h:
5//     A set of functions to generate random numbers according to
6//     bivariate normal (=Gaussian) distribution + special distribution
7//     on disk combining it with bivariate normal distribution
8//
9// Initial coding by Vlastimil Havran, January 2007
10
11#ifndef __RNDGAUSS_H__
12#define __RNDGAUSS_H__
13
14#include "SampleGenerator.h"
15#include "Vector3.h"
16
17#include <assert.h>
18
19
20namespace CHCDemoEngine
21{
22// Function: GaussianOn2D
23// Here we generate the Gaussian distribution on the 2D domain
24// (=bivariate normal distribution) given the uniformly distributed random
25// numbers in the range [0-1)x[0-1) (bivariate uniform distribution).
26// We specify also standard deviation (sigma) of the normal distribution.
27// The result has a mean value <0.0f, 0.0f>. We use Box-Muller transform
28// in polar form.
29// Please note that in the distance from mean value this is true:
30// the distance = 1 x sigma ... we have 68.25% of generated points
31//              = 2 x sigma ... we have 95.45% of generated points
32//              = 3 x sigma ... we have 99.73% of generated points
33//              = 4 x sigma ... we have 99.99% of generated points
34
35inline void
36GaussianOn2D(const Sample2 &input, // input (RND in interval [0-1)x[0-1))
37                         float sigma,            // standard deviation of gaussian distribution
38                         Sample2 &outputVec)   // resulting vector according to gaussian distr.
39{
40  // Handling zero
41  float xf = input.x;
42  if (xf < 1e-20f)
43    xf = 1e-20f;
44  assert( xf <= 1.0f);
45  assert( (input.yy >= 0.f) && (input.yy <= 1.0f));
46
47  // Here we have to use natural logarithm function !
48  float t = -2.0f * log(xf);
49  assert(t > 0.f);
50  t = sigma * sqrt(t);
51  float phi = 2.0f * M_PI * input.y;
52  outputVec.x = t * cos(phi);
53  outputVec.y = t * sin(phi);
54
55  return;
56}
57
58// Function: PolarGaussianOnDisk
59// Here we generate the Gaussian distribution on the 2D domain on the part
60// of 2D disk. The input of the function is tuple of random
61// numbers in the range [0-1)x[0-1) (bivariate uniform distribution).
62// The result of this function 'outputVec' (in general in the range
63// [-infinity,+infinity]x[-infinity,+infinity], so the point generated
64// according to proposed distribution. The algorithm does not use rejection
65// sampling. We have to specify the radius of 2D circle
66// where the distribution mean value is zero for one variable !!!!
67// Sigma is specified independently, but if you want to have small probability
68// of generating the original point, then consider:
69// the radius = 1 x sigma ... 68.25% points in the distance from sigma from the circle
70//            = 2 x sigma ... 95.45% points in the distance from sigma from the circle
71//            = 3 x sigma ... 99.73% points in the distance from sigma from the circle
72//            = 4 x sigma ... 99.99% points in the distance from sigma from the circle
73// Recommendation: use sigma = radius/3.3f or so (according to visualization)
74
75// This is only helper function
76inline float
77ComputeSigmaFromRadius(float radius)
78{
79  // For standard deviation = 3 we have achieve probability 0.4% that the proximity
80  // of the center of the circle will be covered again by a generated point.
81  return radius / 3.3f;
82}
83
84inline void
85PolarGaussianOnDisk(const Vector3 &input, // input (RND in interval [0-1)x[0-1))
86                                        float sigma,    // standard deviation of gaussian distribution
87                                        float radius,   // standard deviation of gaussian distribution
88                                        Sample2 &outputVec) // result
89{
90  // Handling zero
91  float xf = input.x;
92  if (xf < 1e-20f)
93    xf = 1e-20f;
94  assert( xf <= 1.0f);
95  assert( (input.y >= 0.f) && (input.y <= 1.0f));
96
97  // Here we have to use natural logarithm function !
98  float t = -2.0f * log(xf);
99  assert(t > 0.f);
100  t = sigma * sqrt(t);
101  float phi = 2.0f * M_PI * input.y;
102
103#if 1
104  // This is what Jiri Bittner wanted originally,
105  // another idea how to implement this distribution
106  // First, we generate point as for standard polar
107  // inmplementation
108  outputVec.x = t * cos(phi);
109  outputVec.y = t * sin(phi);
110
111  // Then we generate a point on 2D circle at the distance
112  // of radius
113  float r = input.z; //RND::rand01f();
114  float phi2 = 2.0f * M_PI * r;
115
116  Sample2 c(cos(phi2),sin(phi2));
117 
118  outputVec.x += radius * c.x;
119  outputVec.y += radius * c.y;
120
121#endif
122#if 0
123  // This is what Jiri Bittner wanted originally
124  // however, I cannot make it running correctly !!!
125  // Do not use it at the moment !!! VH 11/1/2007
126  float r = RND::rand01f(); 
127  if (r < 0.5f) {
128    outputVec.x = (radius + t) * cos(phi);
129    outputVec.y = (radius + t) * sin(phi);
130  }
131  else {
132    // going inside the cirle
133    outputVec.x = (radius - t) * cos(phi);
134    outputVec.y = (radius - t) * sin(phi);   
135  }
136#endif
137 
138  return;
139}
140
141}
142#endif // __RND_H__
Note: See TracBrowser for help on using the repository browser.