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