├── Samples
└── .gitkeep
├── .gitignore
├── README.pdf
├── Example.unity
├── lib
├── MersenneTwister.cs
├── ExponentialDistribution.cs
├── PowerLaw.cs
├── RandomSquare.cs
├── GammaDistribution.cs
├── DiceRoll.cs
├── SpecialFunctions.cs
├── PoissonDistribution.cs
├── RandomDisk.cs
├── WaveToRgb.cs
├── RandomCube.cs
├── RandomSphere.cs
├── NormalDistribution.cs
└── ShuffleBagCollection.cs
├── ExampleFiles
├── RotateAround.cs
└── ExampleUnityRandom.cs
├── Editor
├── UnityRandomEditorDraw.cs
└── UnityRandomEditorWindow.cs
├── UnityRandom.cs
└── README.textile
/Samples/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | Samples/*.txt
3 |
4 |
--------------------------------------------------------------------------------
/README.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kakao74/UnityRandom/HEAD/README.pdf
--------------------------------------------------------------------------------
/Example.unity:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kakao74/UnityRandom/HEAD/Example.unity
--------------------------------------------------------------------------------
/lib/MersenneTwister.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kakao74/UnityRandom/HEAD/lib/MersenneTwister.cs
--------------------------------------------------------------------------------
/lib/ExponentialDistribution.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace URandom
4 | {
5 | public static class ExponentialDistribution
6 | {
7 | // FROM http://stackoverflow.com/questions/2106503/pseudorandom-number-generator-exponential-distribution
8 | public static float Normalize( float randx, float lambda )
9 | {
10 | return Convert.ToSingle((Math.Log(1-randx) / (-lambda)));
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/lib/PowerLaw.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | //
4 | // FROM HERE:
5 | //
6 | // http://stackoverflow.com/questions/918736/random-number-generator-that-produces-a-power-law-distribution
7 | //
8 | //
9 |
10 | namespace URandom
11 | {
12 | public static class PowerLaw
13 | {
14 | public static double Normalize( float x, float t, float min, float max)
15 | {
16 | return Math.Pow( ( Math.Pow(max, (t + 1)) - Math.Pow(min,(t+1)) ) * x + Math.Pow(min,(t+1)) , ( 1 / (t+1) ));
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/ExampleFiles/RotateAround.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | public class RotateAround : MonoBehaviour {
5 |
6 | public Transform pivotPoint;
7 | public bool rotating = true;
8 |
9 | void Start()
10 | {
11 | if (!pivotPoint)
12 | Debug.LogError("I need an object to rotate around");
13 | }
14 |
15 |
16 | // Update is called once per frame
17 | void Update ()
18 | {
19 | if (rotating)
20 | transform.RotateAround(pivotPoint.position, Vector3.up, 20 * Time.deltaTime);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/RandomSquare.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using NPack;
4 |
5 | namespace URandom
6 | {
7 | public static class RandomSquare
8 | {
9 | public static Vector2 Area( ref NPack.MersenneTwister _rand )
10 | {
11 | // Move to -1, 1 space as for CIRCLE and SPHERE
12 | return new Vector2((2*_rand.NextSingle(true) - 1), (2*_rand.NextSingle(true) - 1));
13 | }
14 |
15 | public static Vector2 Area( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t )
16 | {
17 | float x,y;
18 | x = y = 0;
19 | switch (n) {
20 | case UnityRandom.Normalization.STDNORMAL:
21 | x = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
22 | y = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
23 | break;
24 | case UnityRandom.Normalization.POWERLAW:
25 | x = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
26 | y = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
27 | break;
28 | default:
29 | x = _rand.NextSingle(true);
30 | y = _rand.NextSingle(true);
31 | break;
32 | }
33 |
34 | // Move to -1, 1 space as for CIRCLE and SPHERE
35 | return new Vector2((2*x - 1), (2*y - 1));
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/lib/GammaDistribution.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NPack;
3 |
4 | namespace URandom
5 | {
6 | // Returns a deviate distributed as a gamma distribution of integer of order ia, i.e. the waiting time for the iath event in a Poisson process of unit mean
7 | // Use _rand as a source of uniform deviates
8 | // http://www.nrbook.com/a/bookcpdf.php
9 | public static class GammaDistribution
10 | {
11 | public static float Normalize(ref NPack.MersenneTwister _rand, int ia)
12 | {
13 | int j;
14 | float am, e, s, v1, v2, x, y;
15 |
16 | if (ia < 1)
17 | throw new ArgumentException("Error in Gamma Distribution. Argument ia should be an integer > 1");
18 |
19 | if (ia < 6) {
20 | // use direct method, addin waiting times
21 | x = 1.0f;
22 | for (j=1; j<=ia; j++) x *= _rand.NextSingle(true);
23 | x = (float) - (Math.Log(x));
24 | } else {
25 | do {
26 | do {
27 | // This four lines generate the tanget of random angle
28 | // Equivalent to y = tan( pi * rand())
29 | do {
30 | v1 = _rand.NextSingle(true);
31 | v2 = 2.0f * _rand.NextSingle(true) - 1.0f;
32 | } while (v1 * v1+v2 * v2 > 1.0f);
33 | y = v2/v1;
34 | am = ia-1;
35 | s = (float) Math.Sqrt(2.0*am+1.0f);
36 | x = s * y + am;
37 | // We decide wheter to reject x, Reject in 0 probability region
38 | } while (x <= 0.0f);
39 | e = (float) ((1.0f + y*y) * Math.Exp(am * Math.Log(x/am) -s*y));
40 | } while (_rand.NextSingle(true) > e);
41 | }
42 | return x;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/lib/DiceRoll.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Linq;
4 | using NPack;
5 |
6 | namespace URandom
7 | {
8 | public class DiceRoll
9 | {
10 | // STORE DICE RESULTS in an ARRAYLIST
11 | private int[] _result;
12 | public int[] result
13 | {
14 | get
15 | {
16 | return _result;
17 | }
18 | }
19 |
20 | public enum DiceType
21 | {
22 | D2 = 2,
23 | D3 = 3,
24 | D4 = 4,
25 | D6 = 6,
26 | D8 = 8,
27 | D10 = 10,
28 | D12 = 12,
29 | D20 = 20,
30 | D30 = 30,
31 | D100 = 100
32 | }
33 |
34 | private DiceType _dice_type = DiceType.D6;
35 | public DiceType type
36 | {
37 | get { return _dice_type; }
38 | }
39 |
40 | private int _size = 1;
41 | public int size
42 | {
43 | get { return _size; }
44 | }
45 |
46 | // CONSTRUCTOR
47 | public DiceRoll(int size, DiceType type, ref NPack.MersenneTwister _rand)
48 | {
49 | if (size < 1) throw new ArgumentOutOfRangeException ("Number of dices shlud be > 0");
50 | init(size,type,ref _rand);
51 | }
52 |
53 | // INIT
54 | private void init(int size, DiceType type, ref NPack.MersenneTwister _rand)
55 | {
56 | _result = new int[size];
57 | _dice_type = type;
58 | _size = size;
59 |
60 | for (int i = 0; i < _size; i++) {
61 | // Cast enum to int to get the value
62 | _result[i] = _rand.Next( 1, (int) type);
63 | }
64 | }
65 |
66 | // DICETYPE TO STRING
67 | public String TypeToString()
68 | {
69 | return _size + _dice_type.ToString();
70 | }
71 |
72 | // DICEROLL TO STRING
73 | public String RollToString()
74 | {
75 | String s = "";
76 | for (int i = 0; i < _size; i++) {
77 | s += _result[i].ToString();
78 | if (i != (_size -1)) s += ", ";
79 | }
80 | return s;
81 | }
82 |
83 | public int Sum()
84 | {
85 | return _result.Sum();
86 | }
87 |
88 | }
89 | }
--------------------------------------------------------------------------------
/lib/SpecialFunctions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | /////////////////////////////////////////////////////////////////////////////
4 | // //
5 | // Unity Random //
6 | // //
7 | // special Functions from http://www.nrbook.com/a/bookcpdf/c6-1.pdf //
8 | // //
9 | // //
10 | /////////////////////////////////////////////////////////////////////////////
11 |
12 | namespace URandom
13 | {
14 | public static class SpecialFunctions
15 | {
16 | // Builtin arrays (native .NET arrays), are extremely fast and efficient but they can not be resized.
17 | static double[] cof = new double[6] {
18 | 76.18009172947146,
19 | -86.50532032941677,
20 | 24.01409824083091,
21 | -1.231739572450155,
22 | 0.1208650973866179e-2,
23 | -0.5395239384953e-5};
24 |
25 | // 6.1 Gamma Function, Beta Function, Factorials, Binomial Coefficients
26 | // http://www.nrbook.com/a/bookcpdf/c6-1.pdf
27 | // Return the natural log of a gamma function for xx > 0
28 | // Internal arithmetic in double precision.
29 | public static double gammln( double xx )
30 | {
31 | double x,y,tmp,ser;
32 |
33 | int j;
34 |
35 | y = x = xx;
36 | tmp = x + 5.5;
37 | tmp -= (x + 0.5) * Math.Log(tmp);
38 | ser=1.000000000190015;
39 |
40 | for (j=0;j<=5;j++)
41 | {
42 | ser += cof[j]/++y;
43 | }
44 |
45 | return -tmp+Math.Log(2.5066282746310005 * ser/x );
46 | }
47 |
48 | // Scale range old to any range
49 | public static float ScaleFloatToRange(float x, float newMin, float newMax, float oldMin, float oldMax)
50 | {
51 | return (x / ((oldMax - oldMin) / (newMax - newMin))) + newMin;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/lib/PoissonDistribution.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NPack;
3 |
4 | //
5 | // NEW VERSION FROM NUMERICAL RECIPES http://www.nrbook.com/a/bookcpdf.php
6 | // 7.3 Rejection Method: Gamma, Poisson, Binomial Deviates
7 |
8 | namespace URandom
9 | {
10 | public static class PoissonDistribution
11 | {
12 |
13 | // return as a floating point number an integer value that is a random deviate drawn
14 | // from a Possion Distribution of mean xm using randx as a source of uniform deviates
15 | public static float Normalize( ref NPack.MersenneTwister _rand, float xm)
16 | {
17 | // Davide Rambaldi: all moved to double precision
18 | double sq, alxm, g, oldm; // oldm is a flag for wheter xm has changed or not sincle last call
19 | sq = alxm = g = oldm = (-1.0);
20 | double em, t, y;
21 |
22 | if (xm < 12.0f) { // Use direct method
23 | if (xm != oldm) {
24 | oldm = xm;
25 | g = Math.Exp(-xm); // if x is new, compute the exponential
26 | }
27 | em = -1;
28 | t = 1.0f;
29 | // Instead of adding exponential deviates it is equivalent to multiply unifomr deviates
30 | // We never actually take the log, we compare the precomupted exponential
31 | do {
32 | ++em;
33 | t *= _rand.NextSingle(true);
34 | } while (t > g);
35 | } else {
36 | // Use REJECTION method
37 | // xm has changed?
38 | if ( xm != oldm) {
39 | oldm = xm;
40 | sq = Math.Sqrt(2.0 * xm);
41 | alxm = Math.Log(xm);
42 |
43 | // Gammln is the natural log of a gamma function
44 | g = xm * alxm - SpecialFunctions.gammln(xm + 1.0f);
45 | }
46 | do {
47 | do {
48 | // y is the deviate from a Lorentzian comparison function
49 | y = Math.Tan(Math.PI*_rand.NextSingle(true));
50 | em=sq*y+xm;
51 | } while (em < 0.0);
52 | em = Math.Floor(em);
53 | t = 0.9 * (1.0+y*y) * Math.Exp(em*alxm-SpecialFunctions.gammln(em+1.0f)-g);
54 | } while (_rand.NextSingle(true) > t);
55 | }
56 | return (float) em;
57 | }
58 |
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/lib/RandomDisk.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using NPack;
4 |
5 | namespace URandom
6 | {
7 | public static class RandomDisk
8 | {
9 | // CIRCLE with R=1
10 | public static Vector2 Circle( ref NPack.MersenneTwister _rand )
11 | {
12 | float t = (float) _rand.Next();
13 | float _2pi = (float) Math.PI * 2;
14 | float a = SpecialFunctions.ScaleFloatToRange(t, 0, _2pi, 0, Int32.MaxValue);
15 | return new Vector2( (float) Math.Cos(a) , (float) Math.Sin(a));
16 | }
17 |
18 | public static Vector2 Circle( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t )
19 | {
20 | float r;
21 | switch (n) {
22 | case UnityRandom.Normalization.STDNORMAL:
23 | r = SpecialFunctions.ScaleFloatToRange( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), 0, Int32.MaxValue, 0, 1);
24 | break;
25 | case UnityRandom.Normalization.POWERLAW:
26 | r = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, Int32.MaxValue);
27 | break;
28 | default:
29 | r = (float) _rand.Next();
30 | break;
31 | }
32 | float _2pi = (float) Math.PI * 2;
33 | float a = SpecialFunctions.ScaleFloatToRange(r, 0, _2pi, 0, Int32.MaxValue);
34 | return new Vector2( (float) Math.Cos(a) , (float) Math.Sin(a));
35 | }
36 |
37 |
38 | public static Vector2 Disk( ref NPack.MersenneTwister _rand )
39 | {
40 | // t [0,1] , Theta [0,2pi)
41 | double t = _rand.NextSingle(true);
42 | // in range [0,1) then multiply this number by k to get a random number in the range [0,k)
43 | double theta = _rand.NextSingle(false) * 2 * Math.PI;
44 | return new Vector2( (float) (Math.Sqrt(t) * Math.Cos(theta)), (float) (Math.Sqrt(t) * Math.Sin(theta)) );
45 | }
46 |
47 | public static Vector2 Disk( ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float temp )
48 | {
49 | double t, theta;
50 |
51 | switch (n) {
52 | case UnityRandom.Normalization.STDNORMAL:
53 | t = NormalDistribution.Normalize(_rand.NextSingle(true), temp);
54 | theta = NormalDistribution.Normalize(_rand.NextSingle(true), temp) * 2 * Math.PI;
55 | break;
56 | case UnityRandom.Normalization.POWERLAW:
57 | t = PowerLaw.Normalize(_rand.NextSingle(true), temp, 0, 1);
58 | theta = PowerLaw.Normalize(_rand.NextSingle(true), temp, 0, 1) * 2 * Math.PI;
59 | break;
60 | default:
61 | t = (float) _rand.NextSingle(true);
62 | theta = _rand.NextSingle(false) * 2 * Math.PI;
63 | break;
64 | }
65 |
66 | return new Vector2( (float) (Math.Sqrt(t) * Math.Cos(theta)), (float) (Math.Sqrt(t) * Math.Sin(theta)) );
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/lib/WaveToRgb.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | namespace URandom
5 | {
6 | public class WaveToRgb
7 | {
8 | // CONSTS
9 | public const float MinVisibleWaveLength = 350.0f;
10 | public const float MaxVisibleWaveLength = 650.0f;
11 | public const float Gamma = 0.80f;
12 | public const int IntesityMax = 255;
13 |
14 | // CORE
15 | public static Color LinearToRgb( float linearvalue)
16 | {
17 | return WaveLengthToRgb(GetWaveLengthFromDataPoint( linearvalue, 0.0f, 1.0f));
18 | }
19 |
20 | // WAVE LENGTH ALGORITHM
21 | private static float GetWaveLengthFromDataPoint(float x, float min, float max)
22 | {
23 | // convert data in the range min - max to wavelength
24 | float result = (x - min) / (max - min) * (MaxVisibleWaveLength - MinVisibleWaveLength) + MinVisibleWaveLength;
25 | return result;
26 | }
27 |
28 | // ADJUST ALGORITHM
29 | private static int Adjust( float color, float factor)
30 | {
31 | if (color == 0.0f) {
32 | return 0;
33 | } else {
34 | return (int) Mathf.Round( IntesityMax * Mathf.Pow(color * factor, Gamma) );
35 | }
36 | }
37 |
38 | // WAVELENGTH TO RGB
39 | private static Color WaveLengthToRgb( float wave )
40 | {
41 | wave = Mathf.Floor(wave);
42 |
43 | float r = 0.0f;
44 | float g = 0.0f;
45 | float b = 0.0f;
46 | float factor = 0.0f;
47 |
48 | if (wave >= 380 && wave < 440) {
49 | r = - (wave - 440) / (440 -380);
50 | g = 0.0f;
51 | b = 1.0f;
52 | } else if (wave >= 440 && wave < 490) {
53 | r = 0.0f;
54 | g = (wave - 440) / (490 - 440);
55 | b = 1.0f;
56 | } else if (wave >= 490 && wave < 510) {
57 | r = 0.0f;
58 | g = 1.0f;
59 | b = - (wave - 510) / (510 - 490);
60 | } else if (wave >= 510 && wave < 580) {
61 | r = (wave - 510) / (580 - 510);
62 | g = 1.0f;
63 | b = 0.0f;
64 | } else if (wave >= 580 && wave < 645) {
65 | r = 1.0f;
66 | g = - (wave - 645) / (645 - 580);
67 | b = 0.0f;
68 | } else if (wave >= 645 && wave <= 780) {
69 | r = 1.0f;
70 | g = 0.0f;
71 | b = 0.0f;
72 | } else {
73 | r = 0.0f;
74 | g = 0.0f;
75 | b = 0.0f;
76 | }
77 |
78 | // Let the intensity fall off near the vision limits
79 | if (wave >= 380 && wave < 420) {
80 | factor = 0.3f + 0.7f * ( wave - 380) / (420 - 380);
81 | } else if (wave >= 420 && wave < 700) {
82 | factor = 1.0f;
83 | } else if (wave >= 700 && wave <= 780) {
84 | factor = 0.3f + 0.7f * (780 - wave) / (780 - 700);
85 | } else {
86 | factor = 0.0f;
87 | }
88 |
89 | r = Adjust(r, factor);
90 | g = Adjust(g, factor);
91 | b = Adjust(b, factor);
92 |
93 | // come back to 0.0 - 1.0
94 | r = r / 255;
95 | g = g / 255;
96 | b = b / 255;
97 |
98 | Color newColor = new Color(r,g,b);
99 | return newColor;
100 | }
101 | }
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/lib/RandomCube.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using NPack;
4 |
5 | namespace URandom
6 | {
7 | public static class RandomCube
8 | {
9 | public static Vector3 Surface(ref NPack.MersenneTwister _rand)
10 | {
11 | // Move to -1, 1 space as for CIRCLE and SPHERE
12 | Vector3 pos = GetPointOnCubeSurface(_rand.NextSingle(true),_rand.NextSingle(true),_rand.Next(5));
13 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1);
14 | }
15 |
16 | public static Vector3 Surface(ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t)
17 | {
18 | Vector3 pos = new Vector3();
19 | switch (n) {
20 | case UnityRandom.Normalization.STDNORMAL:
21 | pos = GetPointOnCubeSurface(
22 | (float) NormalDistribution.Normalize(_rand.NextSingle(true), t),
23 | (float) NormalDistribution.Normalize(_rand.NextSingle(true), t),
24 | _rand.Next(5));
25 | break;
26 | case UnityRandom.Normalization.POWERLAW:
27 | pos = GetPointOnCubeSurface(
28 | (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1),
29 | (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1),
30 | _rand.Next(5));
31 | break;
32 | default:
33 | pos = GetPointOnCubeSurface(_rand.NextSingle(true),_rand.NextSingle(true),_rand.Next(5));
34 | break;
35 | }
36 |
37 | // Move to -1, 1 space as for CIRCLE and SPHERE
38 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1);
39 | }
40 |
41 | // This should work: FIXME?
42 | // take 3 random numbers, use 2 for coordinates, the last one to select which face.
43 | private static Vector3 GetPointOnCubeSurface( float xx, float yy, int side)
44 | {
45 | float x,y,z;
46 |
47 | // SIDES MAP
48 | switch (side) {
49 | case 0: z = 0; x = xx; y = yy; break;
50 | case 1: z = 1; x = xx; y = yy; break;
51 | case 2: z = xx; x = yy; y = 0; break;
52 | case 3: z = xx; x = yy; y = 1; break;
53 | case 4: z = xx; y = yy; x = 0; break;
54 | case 5: z = xx; y = yy; x = 1; break;
55 | default: x = 0; y = 0; z = 0; break;
56 | }
57 |
58 | return new Vector3(x,y,z);
59 | }
60 |
61 | public static Vector3 Volume(ref NPack.MersenneTwister _rand)
62 | {
63 | Vector3 pos = new Vector3(_rand.NextSingle(true), _rand.NextSingle(true), _rand.NextSingle(true));
64 | // Move to -1, 1 space as for CIRCLE and SPHERE
65 | return new Vector3((2*pos.x)-1, (2*pos.y)-1, (2*pos.z)-1);
66 | }
67 |
68 | public static Vector3 Volume(ref NPack.MersenneTwister _rand, UnityRandom.Normalization n, float t)
69 | {
70 | float x, y, z;
71 | x = y = z = 0;
72 | switch (n) {
73 | case UnityRandom.Normalization.STDNORMAL:
74 | x = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
75 | y = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
76 | z = (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
77 | break;
78 | case UnityRandom.Normalization.POWERLAW:
79 | x = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
80 | y = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
81 | z = (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
82 | break;
83 | default:
84 | x = _rand.NextSingle(true);
85 | y = _rand.NextSingle(true);
86 | z = _rand.NextSingle(true);
87 | break;
88 | }
89 | // Move to -1, 1 space as for CIRCLE and SPHERE
90 | return new Vector3((2*x)-1, (2*y)-1, (2*z)-1);
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/lib/RandomSphere.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using NPack;
4 |
5 | namespace URandom
6 | {
7 | public static class RandomSphere
8 | {
9 | // RADIUS = 1
10 |
11 | // Marsaglia Method (1972) I use for Surface and Volume
12 | // FROM http://stackoverflow.com/questions/5531827/random-point-on-a-given-sphere
13 | // ALSO: http://mathworld.wolfram.com/SpherePointPicking.html
14 | // 1. Pick a random point inside the [-1,1]x[-1,1]x[-1,1] cube
15 | // 2. If x*x + y*y + z*z > 1 repeat from 1
16 | // 3. Normalize dividing x, y and z by Math.sqrt(x*x + y*y + z*z)
17 |
18 | public static Vector3 Surface(ref NPack.MersenneTwister _rand)
19 | {
20 | Vector3 pos = PickCubePoints(ref _rand);
21 | while ( IsNotOnSurface(pos) )
22 | {
23 | pos = PickCubePoints(ref _rand);
24 | }
25 | return Normalize(pos);
26 | }
27 |
28 | public static Vector3 Volume(ref NPack.MersenneTwister _rand)
29 | {
30 | Vector3 pos = PickCubePoints(ref _rand);
31 | while ( isNotInsideSphere(pos) )
32 | {
33 | pos = PickCubePoints(ref _rand);
34 | }
35 | return pos;
36 | }
37 |
38 | private static Vector3 PickCubePoints( ref NPack.MersenneTwister _rand )
39 | {
40 |
41 | float x = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 );
42 | float y = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 );
43 | float z = SpecialFunctions.ScaleFloatToRange( _rand.NextSingle(true), -1, 1, 0, 1 );
44 |
45 | return new Vector3(x,y,z);
46 | }
47 |
48 | private static bool isNotInsideSphere(Vector3 pos)
49 | {
50 | return( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) > 1 );
51 | }
52 |
53 | private static bool IsNotOnSurface(Vector3 pos)
54 | {
55 | return ( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) > 1 );
56 | }
57 |
58 | private static Vector3 Normalize( Vector3 pos)
59 | {
60 | float k = (float) Math.Sqrt( (pos.x * pos.x) + (pos.y * pos.y) + (pos.z * pos.z) );
61 | return new Vector3( pos.x / k, pos.y / k, pos.z / k );
62 | }
63 |
64 | /// FROM: http://unifycommunity.com/wiki/index.php?title=UnitSphere
65 | ///
66 | /// Returns a point on the unit sphere that is within a cone along the z-axis
67 | ///
68 | /// [0..180] specifies the angle of the cone.
69 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand)
70 | {
71 | float angle1 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),0.0f, Mathf.PI*2, 0, 1);
72 | float angle2 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true), 0.0f,spotAngle * Mathf.Deg2Rad, 0, 1);
73 | Vector3 V = new Vector3(Mathf.Sin(angle1),Mathf.Cos(angle1),0);
74 | V *= Mathf.Sin(angle2);
75 | V.z = Mathf.Cos(angle2);
76 | return V;
77 | }
78 |
79 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM
80 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation)
81 | {
82 | return orientation * GetPointOnCap(spotAngle, ref _rand);
83 | }
84 |
85 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM
86 | public static Vector3 GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Transform relativeTo, float radius)
87 | {
88 | return relativeTo.TransformPoint( GetPointOnCap(spotAngle, ref _rand)*radius );
89 | }
90 |
91 | /// FROM: http://unifycommunity.com/wiki/index.php?title=UnitSphere
92 | ///
93 | /// Returns a point on the unit sphere that is within the outer cone along the z-axis
94 | /// but not inside the inner cone. The resulting area describes a ring on the sphere surface.
95 | ///
96 | /// [0..180] specifies the inner cone that should be excluded.
97 | /// [0..180] specifies the outer cone that should be included.
98 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand)
99 | {
100 | float angle1 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),0.0f, Mathf.PI*2, 0, 1);
101 | float angle2 = SpecialFunctions.ScaleFloatToRange(_rand.NextSingle(true),innerSpotAngle, outerSpotAngle, 0, 1) * Mathf.Deg2Rad;
102 | Vector3 V = new Vector3(Mathf.Sin(angle1),Mathf.Cos(angle1),0);
103 | V *= Mathf.Sin(angle2);
104 | V.z = Mathf.Cos(angle2);
105 | return V;
106 | }
107 |
108 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM
109 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation)
110 | {
111 | return orientation * GetPointOnRing(innerSpotAngle, outerSpotAngle, ref _rand);
112 | }
113 |
114 | // FIXME: NOT YET IMPLEMENTED IN UNITYRANDOM
115 | public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Transform relativeTo, float radius)
116 | {
117 | return relativeTo.TransformPoint( GetPointOnRing(innerSpotAngle, outerSpotAngle, ref _rand)*radius );
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/ExampleFiles/ExampleUnityRandom.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | public class ExampleUnityRandom : MonoBehaviour
5 | {
6 | private UnityRandom urand;
7 |
8 | private bool rotate = false;
9 | public float sphereRadius = 20.0f;
10 | public int max_objects = 1000;
11 | public int seed = 123456;
12 |
13 | /* LateUpdate is called after all Update functions have been called. */
14 | void LateUpdate ()
15 | {
16 | if (Input.GetButtonDown("Jump")) {
17 | rotate = !rotate;
18 | ToggleRotation();
19 | }
20 | }
21 |
22 | private void ToggleRotation()
23 | {
24 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
25 | foreach (GameObject item in objs)
26 | {
27 | item.GetComponent().rotating = rotate;
28 | }
29 | }
30 |
31 | // GUI
32 | void OnGUI()
33 | {
34 | GUILayout.BeginVertical("box");
35 |
36 | GUILayout.BeginHorizontal();
37 | GUILayout.FlexibleSpace();
38 | GUILayout.Label("UNITYRANDOM POINT EXAMPLES");
39 | GUILayout.FlexibleSpace();
40 | GUILayout.EndHorizontal();
41 |
42 | GUILayout.BeginHorizontal();
43 | GUILayout.FlexibleSpace();
44 | GUILayout.Label("SET A SEED: " + seed);
45 | GUILayout.FlexibleSpace();
46 | GUILayout.EndHorizontal();
47 |
48 | // I cut the SEED space for the GUI
49 | // Because the Slider get crazy with Int32.MaxValue (it goes back to Int.32.MinValue)
50 | seed = (int) GUILayout.HorizontalSlider(seed, 0, UnityRandom.max_seed - 1000);
51 |
52 | if (GUILayout.Button("IN SPHERE SURFACE")) ExampleInSpheres();
53 | if (GUILayout.Button("IN CIRCLE")) ExampleInCircle();
54 | if (GUILayout.Button("IN DISK")) ExampleInDisk();
55 | if (GUILayout.Button("IN SPHERE VOLUME")) ExampleInSphere();
56 | if (GUILayout.Button("IN CUBE")) ExampleInCube();
57 | if (GUILayout.Button("ON CUBE")) ExampleOnCube();
58 | if (GUILayout.Button("ON CAP")) ExampleOnCap();
59 | if (GUILayout.Button("ON RING")) ExampleOnRing();
60 | GUILayout.BeginHorizontal();
61 | GUILayout.FlexibleSpace();
62 | GUILayout.Label("TOGGLE ROTATION WITH JUMP");
63 | GUILayout.FlexibleSpace();
64 | GUILayout.EndHorizontal();
65 |
66 | GUILayout.EndVertical();
67 | }
68 |
69 | private void ExampleOnRing()
70 | {
71 | InitRandom();
72 | CleanUp();
73 | MakeObjects();
74 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
75 | foreach (GameObject item in objs)
76 | {
77 | item.transform.position = ScalePosition(urand.PointOnRing(20.0f, 30.0f));
78 | }
79 | }
80 |
81 | private void ExampleOnCap()
82 | {
83 | InitRandom();
84 | CleanUp();
85 | MakeObjects();
86 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
87 | foreach (GameObject item in objs)
88 | {
89 | item.transform.position = ScalePosition(urand.PointOnCap(30.0f));
90 | }
91 | }
92 |
93 | // INIT a new UnityRandom object with a random seed
94 | private void InitRandom()
95 | {
96 | urand = new UnityRandom(seed);
97 | }
98 |
99 | private void ExampleInCircle()
100 | {
101 | InitRandom();
102 | CleanUp();
103 | MakeObjects();
104 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
105 | foreach (GameObject item in objs)
106 | {
107 | item.transform.position = ScalePosition(urand.PointInACircle());
108 | }
109 | }
110 |
111 | private void ExampleInDisk()
112 | {
113 | InitRandom();
114 | CleanUp();
115 | MakeObjects();
116 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
117 | foreach (GameObject item in objs)
118 | {
119 | item.transform.position = ScalePosition(urand.PointInADisk());
120 | }
121 | }
122 |
123 | private void ExampleInSphere()
124 | {
125 | InitRandom();
126 | CleanUp();
127 | MakeObjects();
128 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
129 | foreach (GameObject item in objs)
130 | {
131 | item.transform.position = ScalePosition(urand.PointInASphere());
132 | }
133 | }
134 |
135 | private void ExampleInCube()
136 | {
137 | InitRandom();
138 | CleanUp();
139 | MakeObjects();
140 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
141 | foreach (GameObject item in objs)
142 | {
143 | item.transform.position = ScalePosition(urand.PointInACube());
144 | }
145 | }
146 |
147 | private void ExampleOnCube()
148 | {
149 | InitRandom();
150 | CleanUp();
151 | MakeObjects();
152 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
153 | foreach (GameObject item in objs)
154 | {
155 | item.transform.position = ScalePosition(urand.PointOnACube());
156 | }
157 | }
158 |
159 | private void ExampleInSpheres()
160 | {
161 | InitRandom();
162 | CleanUp();
163 | MakeObjects();
164 | }
165 |
166 | private void CleanUp()
167 | {
168 | // Clear all
169 | GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
170 | foreach (GameObject item in objs)
171 | {
172 | Destroy(item);
173 | }
174 | }
175 |
176 | private void MakeObjects()
177 | {
178 |
179 | // CENTER OF THE SPHERE: x = 0, y = 20, z = 0 I generate an object there
180 | GameObject _pivot = new GameObject();
181 | _pivot.transform.position = new Vector3(0,sphereRadius,0);
182 |
183 | for (int i = 0; i < max_objects; i++)
184 | {
185 | // WE make a small sphere
186 | GameObject _sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
187 | // WE SCALE THE SPHERE
188 | _sphere.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
189 | // TAKE A SCALED RANDOM POSITION
190 | Vector3 pos = ScalePosition(urand.PointOnASphere());
191 | // WE set the sphere position
192 | _sphere.transform.position = pos;
193 | // WE give a tag to the sphere
194 | _sphere.tag = "Player";
195 | // Attach the rotation script
196 | RotateAround _ra = _sphere.AddComponent();
197 | // SET the PIVOT POINT IN SCRIPT
198 | _ra.pivotPoint = _pivot.transform;
199 | // SET the MATERIAL as a RANDOM COLOR
200 | _sphere.renderer.material.color = urand.Rainbow();
201 | }
202 | }
203 |
204 | // CAN BE ADDED IN THE LIBRARY??? FIXME
205 | private Vector3 ScalePosition(Vector3 pos)
206 | {
207 | // WE scale TO 20,20,20
208 | pos = Vector3.Scale(pos, new Vector3(sphereRadius,sphereRadius,sphereRadius));
209 | // WE move UP
210 | pos = pos + new Vector3(0,sphereRadius,0);
211 | return pos;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/Editor/UnityRandomEditorDraw.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 | using System;
4 | using System.Collections;
5 | using System.Text;
6 | using System.IO;
7 | using URandom;
8 |
9 | public class UnityRandomEditorDraw
10 | {
11 | public static Texture2D aaLineTex = null;
12 | public static Texture2D lineTex = null;
13 | public static Texture2D tex = null;
14 |
15 | public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width, bool antiAlias)
16 | {
17 | Color savedColor = GUI.color;
18 | Matrix4x4 savedMatrix = GUI.matrix;
19 |
20 | if (!lineTex)
21 | {
22 | lineTex = new Texture2D(1, 1, TextureFormat.ARGB32, true);
23 | lineTex.SetPixel(0, 1, Color.white);
24 | lineTex.Apply();
25 | }
26 |
27 | if (!aaLineTex)
28 | {
29 | aaLineTex = new Texture2D(1, 3, TextureFormat.ARGB32, true);
30 | aaLineTex.SetPixel(0, 0, new Color(1, 1, 1, 0));
31 | aaLineTex.SetPixel(0, 1, Color.white);
32 | aaLineTex.SetPixel(0, 2, new Color(1, 1, 1, 0));
33 | aaLineTex.Apply();
34 | }
35 |
36 | if (antiAlias) width *= 3;
37 |
38 | float angle = Vector3.Angle(pointB - pointA, Vector2.right) * (pointA.y <= pointB.y?1:-1);
39 |
40 | float m = (pointB - pointA).magnitude;
41 |
42 | if (m > 0.01f)
43 | {
44 | Vector3 dz = new Vector3(pointA.x, pointA.y, 0);
45 |
46 | GUI.color = color;
47 | GUI.matrix = translationMatrix(dz) * GUI.matrix;
48 | GUIUtility.ScaleAroundPivot(new Vector2(m, width), new Vector3(-0.5f, 0, 0));
49 | GUI.matrix = translationMatrix(-dz) * GUI.matrix;
50 | GUIUtility.RotateAroundPivot(angle, Vector2.zero);
51 | GUI.matrix = translationMatrix(dz + new Vector3(width / 2, -m / 2) * Mathf.Sin(angle * Mathf.Deg2Rad)) * GUI.matrix;
52 |
53 | if (!antiAlias)
54 | GUI.DrawTexture(new Rect(0, 0, 1, 1), lineTex);
55 | else
56 | GUI.DrawTexture(new Rect(0, 0, 1, 1), aaLineTex);
57 | }
58 | GUI.matrix = savedMatrix;
59 | GUI.color = savedColor;
60 | }
61 |
62 | private static Matrix4x4 translationMatrix(Vector3 v)
63 | {
64 | return Matrix4x4.TRS(v,Quaternion.identity,Vector3.one);
65 | }
66 |
67 | public static void DrawXYPlot(ArrayList rlist, int width, int height)
68 | {
69 | DrawXYPoints(rlist, 0, 1, width, height);
70 | }
71 |
72 | public static void DrawXYPlot(ArrayList rlist, int width, int height, bool scale)
73 | {
74 | // SCALE
75 | float _min, _max;
76 | if (scale) {
77 | _min = Convert.ToSingle(rlist[0]);
78 | _max = Convert.ToSingle(rlist[rlist.Count - 1]);
79 | } else {
80 | _min = 0;
81 | _max = 1;
82 | }
83 | DrawXYPoints(rlist, _min, _max, width, height);
84 | }
85 |
86 | public static void DrawXYPlot(ArrayList rlist, int width, int height, float min, float max)
87 | {
88 | DrawXYPoints(rlist, min, max, width, height);
89 | }
90 |
91 | private static void DrawXYPoints(ArrayList rlist, float _min, float _max, int width, int height)
92 | {
93 | int counter = 0;
94 | foreach ( object obj in rlist )
95 | {
96 | counter++;
97 | float x, y, val;
98 | val = Convert.ToSingle(obj);
99 | val = ( (val - _min) / (_max - _min) );
100 | y = val * height;
101 | x = counter * (Convert.ToSingle(width) / rlist.Count);
102 | DrawPoint(new Vector2(x,y));
103 | }
104 | }
105 |
106 | public static void DrawV3Plot(ArrayList rlist, int width, int height, UnityRandomEditorWindow.RandomVector3DType _type, float alpha, float beta)
107 | {
108 | foreach ( object obj in rlist )
109 | {
110 | Vector2 _pos = MapTo2D( (Vector3) obj, alpha, beta); // rotation (alpha,beta)
111 | // move from space -1 - 1 to space 0-1
112 | _pos = ((_pos + Vector2.one) * 0.5f);
113 | DrawPoint( Vector2.Scale(_pos, new Vector2(width, height)));
114 | }
115 | }
116 |
117 | private static Vector2 MapTo2D(Vector3 pos, float a, float b)
118 | {
119 | // MAP a 3D point in a 2D space (a and b gives you the rotation)
120 | float ca = (float) Math.Cos(a); float sa = (float) Math.Sin(a);
121 | float cb = (float) Math.Cos(b); float sb = (float) Math.Sin(b);
122 | float xx = ((pos.x * ca) + (pos.y*sa))*cb + pos.z*sb;
123 | float yy = (pos.y*ca) - (pos.x*sa);
124 | return new Vector2(xx,yy);
125 | }
126 |
127 | public static void DrawV2Plot(ArrayList rlist, int width, int height, UnityRandomEditorWindow.RandomVector2DType _type)
128 | {
129 | foreach ( object obj in rlist )
130 | {
131 | Vector2 pos = ((Vector2) obj + Vector2.one) * 0.5f;
132 | switch (_type) {
133 | case UnityRandomEditorWindow.RandomVector2DType.SQUARE:
134 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height)) );
135 | break;
136 | case UnityRandomEditorWindow.RandomVector2DType.CIRCLE:
137 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height) ) );
138 | break;
139 | case UnityRandomEditorWindow.RandomVector2DType.DISK:
140 | DrawPoint( Vector2.Scale( pos, new Vector2(width, height) ) );
141 | break;
142 | default:
143 | break;
144 | }
145 | }
146 | }
147 |
148 | private static void DrawPoint(Vector2 pos)
149 | {
150 | // 1. make a Cross around zero
151 | Vector2 _pointA = new Vector2(0.0f,-1.0f);
152 | Vector2 _pointB = new Vector2(0.0f,1.0f);
153 | Vector2 _pointC = new Vector2(1.0f,0.0f);
154 | Vector2 _pointD = new Vector2(-1.0f,0.0f);
155 |
156 | // 2. move the cross into place
157 | // Y: value
158 | // X: Position
159 | Vector2 _a = _pointA + pos;
160 | Vector2 _b = _pointB + pos;
161 | Vector2 _c = _pointC + pos;
162 | Vector2 _d = _pointD + pos;
163 |
164 | UnityRandomEditorDraw.DrawLine(_a,_b,Color.blue,1.0f,true);
165 | UnityRandomEditorDraw.DrawLine(_c,_d,Color.blue,1.0f,true);
166 | }
167 |
168 | public static void DrawColorPlot(ArrayList rlist, int width, int height)
169 | {
170 | float x,y;
171 | x = y = 0.0f;
172 | float grid_space = 25.0f;
173 | if (!tex) {
174 | tex = new Texture2D(1,1,TextureFormat.ARGB32,false);
175 | }
176 | // make a simple grid
177 | foreach ( object obj in rlist )
178 | {
179 | Vector2 a = new Vector2(x,y);
180 | Vector2 b = new Vector2((x+grid_space),y);
181 | Vector2 c = new Vector2(x,(y+grid_space));
182 | Vector2 d = new Vector2((x+grid_space),(y+grid_space));
183 | DrawPoint(a);
184 | DrawPoint(b);
185 | DrawPoint(c);
186 | DrawPoint(d);
187 |
188 | // make a new texture with the color
189 | tex.SetPixel(0, 1, (Color) obj);
190 | tex.Apply();
191 | GUI.DrawTexture(new Rect(a.x,a.y,grid_space,grid_space), tex);
192 |
193 | if (x < (width - grid_space)) {
194 | x += grid_space;
195 | } else {
196 | x = 0;
197 | y += grid_space;
198 | }
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/lib/NormalDistribution.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | ////////////////////////////////////////////////////////////////////////////
4 | // C# Version Standard CDF //
5 | // //
6 | // This code is free software under the Artistic license. //
7 | // //
8 | /////////////////////////////////////////////////////////////////////////////
9 |
10 | namespace URandom
11 | {
12 |
13 | ///
14 | /// Convert a Uniform Distribution to a Normal Distribution
15 | ///
16 | ///
17 | /// See http://stackoverflow.com/questions/75677/converting-a-uniform-distribution-to-a-normal-distribution for details
18 | ///
19 | public static class NormalDistribution
20 | {
21 | ///
22 | /// Standard Normal CDF
23 | ///
24 | /// The random value
25 | public static double StdNormalCDF(double u)
26 | {
27 | const double m_1_sqrtpi = 0.564189583547756286948;
28 | double msqrt2 = 1.41421356237309504880;
29 | double z, y;
30 |
31 | double[] a = new double [] {
32 | 1.161110663653770e-002,
33 | 3.951404679838207e-001,
34 | 2.846603853776254e+001,
35 | 1.887426188426510e+002,
36 | 3.209377589138469e+003
37 | };
38 |
39 | double[] b = new double [] {
40 | 1.767766952966369e-001,
41 | 8.344316438579620e+000,
42 | 1.725514762600375e+002,
43 | 1.813893686502485e+003,
44 | 8.044716608901563e+003
45 | };
46 |
47 | double[] c = new double [] {
48 | 2.15311535474403846e-8,
49 | 5.64188496988670089e-1,
50 | 8.88314979438837594e00,
51 | 6.61191906371416295e01,
52 | 2.98635138197400131e02,
53 | 8.81952221241769090e02,
54 | 1.71204761263407058e03,
55 | 2.05107837782607147e03,
56 | 1.23033935479799725E03
57 | };
58 |
59 | double[] d = new double [] {
60 | 1.00000000000000000e00,
61 | 1.57449261107098347e01,
62 | 1.17693950891312499e02,
63 | 5.37181101862009858e02,
64 | 1.62138957456669019e03,
65 | 3.29079923573345963e03,
66 | 4.36261909014324716e03,
67 | 3.43936767414372164e03,
68 | 1.23033935480374942e03
69 | };
70 |
71 | double[] p = new double [] {
72 | 1.63153871373020978e-2,
73 | 3.05326634961232344e-1,
74 | 3.60344899949804439e-1,
75 | 1.25781726111229246e-1,
76 | 1.60837851487422766e-2,
77 | 6.58749161529837803e-4
78 | };
79 |
80 | double[] q = new double [] {
81 | 1.00000000000000000e00,
82 | 2.56852019228982242e00,
83 | 1.87295284992346047e00,
84 | 5.27905102951428412e-1,
85 | 6.05183413124413191e-2,
86 | 2.33520497626869185e-3
87 | };
88 |
89 | if (Double.IsNaN(u)) {
90 | return(Double.NaN);
91 | }
92 |
93 | if(Double.IsInfinity(u)) {
94 | return (u < 0 ? 0.0 : 1.0);
95 | }
96 |
97 | y = Math.Abs(u);
98 |
99 | if (y <= 0.46875*msqrt2) {
100 | /* evaluate erf() for |u| <= sqrt(2)*0.46875 */
101 | z = y*y;
102 | y = u*((((a[0]*z+a[1])*z+a[2])*z+a[3])*z+a[4])/((((b[0]*z+b[1])*z+b[2])*z+b[3])*z+b[4]);
103 | return 0.5+y;
104 | }
105 |
106 | z = Math.Exp(-y*y/2)/2;
107 |
108 | if (y <= 4.0) {
109 | /* evaluate erfc() for sqrt(2)*0.46875 <= |u| <= sqrt(2)*4.0 */
110 | y = y/msqrt2;
111 | y = ((((((((c[0]*y+c[1])*y+c[2])*y+c[3])*y+c[4])*y+c[5])*y+c[6])*y+c[7])*y+c[8])
112 | / ((((((((d[0]*y+d[1])*y+d[2])*y+d[3])*y+d[4])*y+d[5])*y+d[6])*y+d[7])*y+d[8]);
113 | y = z*y;
114 | } else {
115 | /* evaluate erfc() for |u| > sqrt(2)*4.0 */
116 | z = z*msqrt2/y;
117 | y = 2/(y*y);
118 | y = y*(((((p[0]*y+p[1])*y+p[2])*y+p[3])*y+p[4])*y+p[5])
119 | /(((((q[0]*y+q[1])*y+q[2])*y+q[3])*y+q[4])*y+q[5]);
120 | y = z*(m_1_sqrtpi-y);
121 | }
122 | return (u < 0.0 ? y : 1-y);
123 | }
124 |
125 | ///
126 | /// Standard Normal INV
127 | ///
128 | /// The random value
129 | public static double StdNormalINV(double p)
130 | {
131 | const double m_sqrt2pi = 2.50662827463100;
132 | double[] a = new double [] {
133 | -3.969683028665376e+01, 2.209460984245205e+02,
134 | -2.759285104469687e+02, 1.383577518672690e+02,
135 | -3.066479806614716e+01, 2.506628277459239e+00
136 | };
137 |
138 | double[] b = new double [] {
139 | -5.447609879822406e+01, 1.615858368580409e+02,
140 | -1.556989798598866e+02, 6.680131188771972e+01,
141 | -1.328068155288572e+01
142 | };
143 |
144 | double[] c = new double [] {
145 | -7.784894002430293e-03, -3.223964580411365e-01,
146 | -2.400758277161838e+00, -2.549732539343734e+00,
147 | 4.374664141464968e+00, 2.938163982698783e+00
148 | };
149 |
150 | double[] d = new double [] {
151 | 7.784695709041462e-03, 3.224671290700398e-01,
152 | 2.445134137142996e+00, 3.754408661907416e+00
153 | };
154 |
155 | double q, t, u;
156 |
157 | if (Double.IsNaN(p) || p > 1.0 || p < 0.0)
158 | {
159 | return(Double.NaN);
160 | }
161 | if (p == 0.0)
162 | {
163 | return Double.NegativeInfinity;
164 | }
165 | if (p == 1.0)
166 | {
167 | return Double.PositiveInfinity;
168 | }
169 |
170 | q = (p < (1-p)) ? p : (1-p);
171 |
172 | if (q > 0.02425) {
173 | /* Rational approximation for central region. */
174 | u = q-0.5;
175 | t = u*u;
176 | u = u*(((((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4])*t+a[5])
177 | /(((((b[0]*t+b[1])*t+b[2])*t+b[3])*t+b[4])*t+1);
178 | } else {
179 | /* Rational approximation for tail region. */
180 | t = Math.Sqrt(-2*Math.Log(q));
181 | u = (((((c[0]*t+c[1])*t+c[2])*t+c[3])*t+c[4])*t+c[5])
182 | /((((d[0]*t+d[1])*t+d[2])*t+d[3])*t+1);
183 | }
184 |
185 | /* The relative error of the approximation has absolute value less
186 | than 1.15e-9. One iteration of Halley's rational method (third
187 | order) gives full machine precision... */
188 |
189 | t = StdNormalCDF(u)-q; /* error */
190 | t = t*m_sqrt2pi*Math.Exp(u*u/2); /* f(u)/df(u) */
191 | u = u-t/(1+u*t/2); /* Halley's method */
192 |
193 | return (p > 0.5 ? -u : u);
194 | }
195 |
196 | ///
197 | /// Normalize
198 | ///
199 | /// The random value
200 | /// Distribution Temperature
201 | public static double Normalize(double rn, float temperature)
202 | {
203 | // Trasformiamo questo numero in una distribuzione normale (CDF inversa, nota anche come Gaussiana, vedi http://en.wikipedia.org/wiki/Normal_distribution)
204 | // facendo l'inversa della cumulative density function su una distribuzione uniforme [0,1] otteniamo una distribuzione normale (-inf,+inf) centrata a zero
205 | // e con deviazione standard 1
206 | double localVal = StdNormalINV(rn);
207 |
208 | // A questo punto passiamo attraverso una funzione sigmoide (o curva logistica) con Lateratura 5
209 | // Questo ci riporta a un campo (0,1), il valore 5 fa si che circa il 90% dei valori restituiti sia tra 0.45 e 0.55, aumentandolo
210 | // la distribuzione si stringe (piu' valori vicini a 0.5), abbassandolo si allarga, ma a differenza di una gaussiana in ogni caso
211 | // il valore restituito e' tra zero e uno.
212 | localVal = localVal / temperature;
213 | localVal = 1.0 / (1.0 + Math.Exp(-localVal));
214 | return(localVal);
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/lib/ShuffleBagCollection.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Adapted from: http://liboxide.svn.sourceforge.net/viewvc/liboxide/trunk/Oxide/Collections/ShuffleBagCollection.cs?view=markup
3 | *
4 | * davide.rambaldi AT gmail.com : Changed Random to Mersenne Twister random, changed namespace to URandom
5 | *
6 | */
7 |
8 | /*
9 | * Oxide .NET extensions library
10 | * Copyright (C) 2009 Matthew Scharley and the liboxide team
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU Lesser General Public License as
14 | * published by the Free Software Foundation, either version 3 of the
15 | * License, or (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU Lesser General Public License
23 | * along with this program. If not, see .
24 | */
25 |
26 | /*
27 | * This class is a port and/or based very heavily on the GShuffleBag class
28 | * written by Jos Hirth originally implemented
29 | * in Java.
30 | */
31 |
32 | /*
33 | * This file is also released seperately from the Oxide Library under a
34 | * BSD style licence described at , with the
35 | * following extra provision:
36 | *
37 | * - All the above copyright notices must be kept intact in any source
38 | * code derived from this file.
39 | */
40 |
41 | /*
42 | * Works with any class that subclasses System.Random
43 | *
44 | * There is a Mersenne Twister implementation available from
45 | * http://code.msdn.microsoft.com/MersenneTwister if the default
46 | * implementation is not good enough.
47 | */
48 | using System;
49 | using System.Collections.Generic;
50 | using System.Collections;
51 | using System.Text;
52 | using NPack;
53 |
54 | namespace URandom
55 | {
56 | public sealed class ShuffleBagCollection : IEnumerable
57 | {
58 | private Random m_generator;
59 | private List m_data;
60 | private int m_cursor = -1;
61 | private T m_current = default(T);
62 |
63 | ///
64 | /// Constructs an empty bag with an initial capacity of 10 and the default source of randomness.
65 | ///
66 | public ShuffleBagCollection() : this(10, new MersenneTwister()) { }
67 | ///
68 | /// Constructs an empty bag with an initial capacity of 10 and the specified source of randomness.
69 | ///
70 | /// The random number generator to use
71 | public ShuffleBagCollection(MersenneTwister generator) : this(10, generator) { }
72 | ///
73 | /// Constructs an empty bag with the specified initial capacity and the default source of randomness.
74 | ///
75 | /// The initial capacity to use
76 | /// Thrown if initialCapacity < 0
77 | public ShuffleBagCollection(int initialCapacity) : this(initialCapacity, new MersenneTwister()) { }
78 | ///
79 | /// Creates an empty bag with the specified initial capacity and the specified random number generator.
80 | ///
81 | /// The initial capacity to use
82 | /// The random number generator to use
83 | /// Thrown if initialCapacity < 0
84 | public ShuffleBagCollection(int initialCapacity, MersenneTwister generator)
85 | {
86 | if (initialCapacity < 0)
87 | throw new ArgumentException("Capacity must be a positive integer.", "initialCapacity");
88 |
89 | m_generator = generator;
90 | m_data = new List(initialCapacity);
91 | }
92 |
93 | ///
94 | /// Add an item to the bag once.
95 | ///
96 | /// The item to throw into the bag.
97 | public void Add(T item)
98 | { Add(item, 1); }
99 | ///
100 | /// Adds an item to the bag multiple times.
101 | ///
102 | /// The item to throw into the bag.
103 | /// The number of times it should come back out.
104 | /// Thrown if quantity is not > 0
105 | public void Add(T item, int quantity)
106 | {
107 | if (quantity <= 0)
108 | throw new ArgumentException("Quantity must be a positive integer.", "quantity");
109 |
110 | for (int i = 0; i < quantity; i++)
111 | {
112 | m_data.Add(item);
113 | }
114 |
115 | // Reseting the cursor to the end makes it possible to get freshly added values right away,
116 | // otherwise it would have to finish this run first.
117 | m_cursor = m_data.Count - 1;
118 | }
119 |
120 | ///
121 | /// Pulls an item out of the bag.
122 | ///
123 | /// The next item in the sequence.
124 | public T Next()
125 | {
126 | if (m_cursor < 1)
127 | {
128 | m_cursor = m_data.Count - 1;
129 | m_current = m_data[0];
130 | return m_current;
131 | }
132 |
133 | int index = m_generator.Next(m_cursor);
134 | m_current = m_data[index];
135 | m_data[index] = m_data[m_cursor];
136 | m_data[m_cursor] = m_current;
137 | m_cursor--;
138 | return m_current;
139 | }
140 |
141 | ///
142 | /// The last element that was returned from Next(). Can be null, if Next() has not been called
143 | /// yet.
144 | ///
145 | public T Current
146 | {
147 | get { return m_current; }
148 | }
149 |
150 | ///
151 | /// The current capacity of the underlying storage.
152 | ///
153 | public int Capacity
154 | {
155 | get { return m_data.Capacity; }
156 | }
157 |
158 | ///
159 | /// Reduces the capacity as much as possible to save memory.
160 | ///
161 | public void TrimExcess()
162 | {
163 | m_data.TrimExcess();
164 | }
165 |
166 | ///
167 | /// The number of elements in this bag.
168 | ///
169 | public int Size
170 | {
171 | get { return m_data.Count; }
172 | }
173 |
174 | #region IEnumerable Members
175 |
176 | ///
177 | ///
178 | /// A sequence of random elements from the bag.
179 | IEnumerator IEnumerable.GetEnumerator()
180 | {
181 | for (int i = 0; i <= Size; i++)
182 | {
183 | yield return this.Next();
184 | }
185 | }
186 |
187 | #endregion
188 |
189 | #region IEnumerable Members
190 |
191 | ///
192 | ///
193 | /// A sequence of random elements from the bag.
194 | IEnumerator IEnumerable.GetEnumerator()
195 | {
196 | return ((IEnumerable)this).GetEnumerator();
197 | }
198 |
199 | #endregion
200 | }
201 | }
--------------------------------------------------------------------------------
/UnityRandom.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using NPack;
6 | using URandom;
7 |
8 | /////////////////////////////////////////////////////////////////////////////
9 | // //
10 | // Unity Random //
11 | // //
12 | // This code is free software under the Artistic license. //
13 | // //
14 | // distributions mainly from: http://www.nrbook.com/a/bookcpdf.php //
15 | // //
16 | // //
17 | /////////////////////////////////////////////////////////////////////////////
18 |
19 | public class UnityRandom
20 | {
21 | // STORE MAX SEED VALUE (no access to System)
22 | public static int max_seed = Int32.MaxValue;
23 |
24 | public enum Normalization
25 | {
26 | STDNORMAL = 0,
27 | POWERLAW = 1
28 | }
29 |
30 | private MersenneTwister _rand;
31 |
32 | // THE CONSTRUCTORS
33 | public UnityRandom()
34 | {
35 | _rand = new MersenneTwister();
36 | }
37 |
38 | public UnityRandom(int seed)
39 | {
40 | _rand = new MersenneTwister(seed);
41 | }
42 |
43 | // VALUE Return a Float 0 - 1
44 | public float Value()
45 | {
46 | return _rand.NextSingle(true);
47 | }
48 |
49 | // VALUE Return a Float 0 - 1
50 | public float Value( Normalization n , float t)
51 | {
52 | if (n == Normalization.STDNORMAL) {
53 | return (float) NormalDistribution.Normalize(_rand.NextSingle(true), t);
54 | } else if (n == Normalization.POWERLAW) {
55 | return (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1);
56 | } else {
57 | return _rand.NextSingle(true);
58 | }
59 | }
60 |
61 | // RANGE Return a Float min < x < max
62 | public float Range(Int32 minValue, Int32 maxValue)
63 | {
64 | return _rand.Next(minValue, maxValue);
65 | }
66 |
67 | // RANGE Return a Float min < x < max
68 | public float Range(Int32 minValue, Int32 maxValue, Normalization n, float t)
69 | {
70 | if (n == Normalization.STDNORMAL) {
71 | return SpecialFunctions.ScaleFloatToRange( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t), minValue, maxValue, 0, 1);
72 | } else if (n == Normalization.POWERLAW) {
73 | return (float) PowerLaw.Normalize(_rand.NextSingle(true), t, minValue, maxValue);
74 | } else {
75 | return _rand.Next(minValue, maxValue);
76 | }
77 | }
78 |
79 | // POISSON Return a Float
80 | public float Possion(float lambda)
81 | {
82 | return PoissonDistribution.Normalize( ref _rand, lambda);
83 | }
84 |
85 | // EXPONENTIAL Return a Float
86 | public float Exponential(float lambda)
87 | {
88 | return ExponentialDistribution.Normalize( _rand.NextSingle( false ), lambda );
89 | }
90 |
91 | // GAMMA Return a Float
92 | public float Gamma(float order)
93 | {
94 | return GammaDistribution.Normalize(ref _rand, (int) order);
95 | }
96 |
97 | // POINT IN A SQUARE Return a Vector2
98 | public Vector2 PointInASquare()
99 | {
100 | return RandomSquare.Area(ref _rand);
101 | }
102 |
103 | // POINT IN A SQUARE Return a Vector2
104 | public Vector2 PointInASquare(Normalization n , float t )
105 | {
106 | return RandomSquare.Area(ref _rand, n, t);
107 | }
108 |
109 | // RANDOM POINT IN A CIRCLE centered at 0
110 | // FROM http://mathworld.wolfram.com/CirclePointPicking.html
111 | // Take a number between 0 and 2PI and move to Cartesian Coordinates
112 | public Vector2 PointInACircle()
113 | {
114 | return RandomDisk.Circle(ref _rand);
115 | }
116 |
117 | // RANDOM POINT IN A CIRCLE centered at 0
118 | // FROM http://mathworld.wolfram.com/CirclePointPicking.html
119 | // Take a number between 0 and 2PI and move to Cartesian Coordinates
120 | public Vector2 PointInACircle(Normalization n, float t)
121 | {
122 | return RandomDisk.Circle(ref _rand, n, t);
123 | }
124 |
125 | // RANDOM POINT in a DISK
126 | // FROM http://mathworld.wolfram.com/DiskPointPicking.html
127 | public Vector2 PointInADisk()
128 | {
129 | return RandomDisk.Disk(ref _rand);
130 | }
131 |
132 | // RANDOM POINT in a DISK
133 | // FROM http://mathworld.wolfram.com/DiskPointPicking.html
134 | public Vector2 PointInADisk(Normalization n, float t)
135 | {
136 | return RandomDisk.Disk(ref _rand, n, t);
137 | }
138 |
139 | // RANDOM POINT IN A CUBE. Return a Vector3
140 | public Vector3 PointInACube()
141 | {
142 | return RandomCube.Volume(ref _rand);
143 | }
144 |
145 | // RANDOM POINT IN A CUBE. Return a Vector3
146 | public Vector3 PointInACube(Normalization n, float t)
147 | {
148 | return RandomCube.Volume(ref _rand, n, t);
149 | }
150 |
151 | // RANDOM POINT ON A CUBE. Return a Vector3
152 | public Vector3 PointOnACube()
153 | {
154 | return RandomCube.Surface(ref _rand);
155 | }
156 |
157 | // RANDOM POINT ON A CUBE. Return a Vector3
158 | public Vector3 PointOnACube(Normalization n, float t)
159 | {
160 | return RandomCube.Surface(ref _rand, n, t);
161 | }
162 |
163 | // RANDOM POINT ON A SPHERE. Return a Vector3
164 | public Vector3 PointOnASphere()
165 | {
166 | return RandomSphere.Surface(ref _rand);
167 | }
168 |
169 | // RANDOM POINT ON A SPHERE. Return a Vector3
170 | public Vector3 PointOnASphere(Normalization n, float t)
171 | {
172 | throw new ArgumentException("Normalizations for Sphere is not yet implemented");
173 | }
174 |
175 | // RANDOM POINT IN A SPHERE. Return a Vector3
176 | public Vector3 PointInASphere()
177 | {
178 | return RandomSphere.Volume(ref _rand);
179 | }
180 |
181 | // RANDOM POINT IN A SPHERE. Return a Vector3
182 | public Vector3 PointInASphere(Normalization n, float t)
183 | {
184 | throw new ArgumentException("Normalizations for Sphere is not yet implemented");
185 | }
186 |
187 | // RANDOM POINT IN A CAP. Return a Vector3
188 | // TODO: see RandomSphere GetPointOnCap(float spotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation)
189 | public Vector3 PointOnCap(float spotAngle)
190 | {
191 | return RandomSphere.GetPointOnCap(spotAngle, ref _rand);
192 | }
193 |
194 | public Vector3 PointOnCap(float spotAngle, Normalization n, float t)
195 | {
196 | throw new ArgumentException("Normalizations for PointOnCap is not yet implemented");
197 | }
198 |
199 | // RANDOM POINT IN A RING on a SPHERE. Return a Vector3
200 | // TODO: see RandomSphere public static Vector3 GetPointOnRing(float innerSpotAngle, float outerSpotAngle, ref NPack.MersenneTwister _rand, Quaternion orientation)
201 | public Vector3 PointOnRing(float innerAngle, float outerAngle)
202 | {
203 | return RandomSphere.GetPointOnRing(innerAngle, outerAngle, ref _rand);
204 | }
205 |
206 | public Vector3 PointOnRing(float innerAngle, float outerAngle, Normalization n, float t)
207 | {
208 | throw new ArgumentException("Normalizations for PointOnRing is not yet implemented");
209 | }
210 |
211 | // RANDOM RAINBOW COLOR
212 | public Color Rainbow()
213 | {
214 | return WaveToRgb.LinearToRgb(_rand.NextSingle(true));
215 | }
216 |
217 | // RANDOM RAINBOW COLOR
218 | public Color Rainbow(Normalization n, float t)
219 | {
220 | if (n == Normalization.STDNORMAL) {
221 | return WaveToRgb.LinearToRgb ( (float) NormalDistribution.Normalize(_rand.NextSingle(true), t));
222 | } else if (n == Normalization.POWERLAW) {
223 | return WaveToRgb.LinearToRgb ( (float) PowerLaw.Normalize(_rand.NextSingle(true), t, 0, 1));
224 | } else {
225 | return WaveToRgb.LinearToRgb(_rand.NextSingle(true));
226 | }
227 | }
228 |
229 | // RANDOM DICES
230 | public DiceRoll RollDice(int size, DiceRoll.DiceType type)
231 | {
232 | DiceRoll roll = new DiceRoll(size, type, ref _rand);
233 | //Debug.Log(roll.TypeToString());
234 | //Debug.Log(roll.RollToString());
235 | //Debug.Log(roll.Sum());
236 | return roll;
237 | }
238 |
239 | // START a FLOAT SHUFFLE BAG
240 | // Note the a value can be shuffled with himself
241 | public ShuffleBagCollection ShuffleBag(float[] values)
242 | {
243 | ShuffleBagCollection bag = new ShuffleBagCollection();
244 | foreach (float x in values)
245 | {
246 | bag.Add(x);
247 | }
248 | return bag;
249 | }
250 |
251 | // START a WIGHTED FLOAT SHUFFLE BAG, the trick is the it is added many times
252 | // Note the a value can be shuffled with himself
253 | public ShuffleBagCollection ShuffleBag(Dictionary dict)
254 | {
255 | ShuffleBagCollection bag = new ShuffleBagCollection();
256 | foreach (KeyValuePair x in dict)
257 | {
258 | //Debug.Log(x.Value);
259 | int val = x.Value;
260 | float key = x.Key;
261 | bag.Add( key, val);
262 | }
263 | return bag;
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/README.textile:
--------------------------------------------------------------------------------
1 | h1=. Unity Random
2 |
3 | h3=. Version 1.0
4 |
5 | h2=. Random Numbers for Unity3d
6 |
7 | p. Homepage: http://tucanosoftware.com/projects/unityrandom
8 |
9 | p. Example: http://108.166.95.149/UnityTest/UnityRandomExample/UnityRandomExample.html
10 |
11 | h3. FAQ
12 |
13 | h4. What is this?
14 |
15 | p. In Unity3d there is already a Random number generator based on the *platform-specific* random generator.
16 | Here we present an alternative Random library for *Unity3d* designed to generate uniform Pseudo-Random deviates.
17 | The library use a fast PRNG (*Mersenne-Twister*) to generate: *Floating Numbers* in range [0-1] and in range [n-m], *Vector2* and *Vector3* data types.
18 | The library comes with some special functions designed specifically for a game design framework: *Shuffle Bag*, *Dice*, *Random Color*.
19 |
20 | h4. Which kind of transformations I can apply to the random uniform deviates?
21 |
22 | p. The uniform deviates can be transformed with the distributions: *Standard Normal Distribution* and *Power-Law*. In addition is possible to generate floating random deviates coming from other distributions: *Poisson*, *Exponential* and *Gamma*.
23 |
24 | h4. How I can test the random numbers?
25 |
26 | p. The library add a window to the *Unity3D* editor that allow you to *Test* and *Visualize* your random numbers, Vector2 and Vector3. With the *SAVE* button, you can write the sample of random number to a txt file. This is useful if you need to analyze in deep the distribution of your random numbers with a statistical software.
27 |
28 |
29 | h3. Usage (C#)
30 |
31 | *Initialization*
32 | Initialization with a seed: @UnityRandom urand = new UnityRandom(int seed);@
33 |
34 | *Numbers*
35 | A Random number in range [0-1]: @float val = urand.Value()
36 |
37 | *Transformations*
38 | A Random number in range [0-1] with a Transformation: @float val = urand.Value(UnityRandom.Normalization.STDNORMAL, 5.0f)@
39 |
40 | *Vectors*
41 | A random point in a disk with R=1: @Vector2 pos = urand.PointInADisk()@
42 |
43 | *Colors*
44 | A random color in the range of visible light (rainbow): @Color col = urand.Rainbow()@
45 |
46 | *Dice*
47 | A 2D6 dice roll @DiceRoll roll = urand.RollDice(2,DiceRoll.DiceType.D6)@
48 |
49 | *Shuffle Bag*
50 |
51 | In games or educational programs you often don't want real randomness. Unsurprisingly random it's often a bit too random. You may get some items several times in a row and others too rarely. It's either too easy or too hard. Balancing the weights is hard as well, because each run is too different. And if that wouldn't be already bad enough; it's also difficult to verify the results.
52 |
53 | A shuffle Bag with values: [1,10]
54 |
55 | @float[] shufflebag = {1,2,3,4,5,6,7,8,9,10};@
56 |
57 | @ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag);@
58 |
59 | @float randvalue = thebag.Next()@
60 |
61 | A shuffle bag with weighted values:
62 |
63 | @Dictionary wshufflebag = new Dictionary();@
64 |
65 | @wshufflebag[1] = 5;@
66 |
67 | @wshufflebag[2] = 45;@
68 |
69 | @wshufflebag[3] = 25;@
70 |
71 | @wshufflebag[4] = 25;@
72 |
73 | @ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag); @
74 |
75 | @float randvalue = thebag.Next()@
76 |
77 |
78 |
79 |
80 |
81 |
82 | h3. Documentation
83 |
84 | h4. Initialization
85 |
86 | * Initialization without a seed: @UnityRandom urand = new UnityRandom();@
87 | * Initialization with a seed: @UnityRandom urand = new UnityRandom(int seed);@
88 |
89 | h4. Numbers
90 |
91 | Generation of uniform deviates in any range.
92 |
93 | *Available Transformations*
94 | * @UnityRandom.Normalization.STDNORMAL@ with parameter: @float temperature@
95 | * @UnityRandom.Normalization.POWERLAW@ with parameter: @float power@
96 |
97 | h5. Value
98 |
99 | * A Random number in range [0-1]: @float val = urand.Value()@
100 | * A Random number in range [0-1] with a Transformation: @float val = urand.Value(UnityRandom.Normalization.STDNORMAL, 5.0f)@
101 |
102 | h5. Range
103 |
104 | * A Random number in range [1-100]: @float val = urand.Range(1,100)@
105 | * A Random number in range [m-n] with a Transformation: @float val = urand.Value(0,100,UnityRandom.Normalization.POWERLAW, 5.0f)@
106 |
107 | h5. Poisson
108 |
109 | * The Poisson distribution (pronounced [pwasɔ̃]) is a discrete probability distribution that expresses the probability of a given number of events occurring in a fixed interval of time and/or space if these events occur with a known average rate and independently of the time since the last event. Example: @float val = urand.Poisson(5.0f)@
110 |
111 | h5. Exponential
112 |
113 | * The Exponential distribution describes the time between events in a Poisson process, i.e. a process in which events occur continuously and independently at a constant average rate. Example: @float val = urand.Exponential(5.0f)@
114 |
115 | h5. Gamma
116 |
117 | * The gamma distribution, like the lognormal distribution, is an alternative to consider for ecological variables that seem to be highly skewed. Example: @float val = urand.Gamma(5.0f)@
118 |
119 | h4. Vector2
120 |
121 | generation of Unity Vector2 Objects.
122 |
123 | h5. Square
124 |
125 | * A random *Vector2* point in a square with L=1: @Vector2 pos = urand.PointInASquare()@
126 | * A random *Vector2* point in a square with L=1 *normalized*: @Vector2 pos = urand.PointInASquare(UnityRandom.Normalization.STDNORMAL, 5.0f)@
127 |
128 | h5. Disk/Circle
129 |
130 | * A random *Vector2* point in a circle (in the circle *perimeter*) with R=1: @Vector2 pos = urand.PointInACircle()@
131 | * A random *Vector2* point in a circle (in the circle *perimeter*) with R=1 *normalized*: @Vector2 pos = urand.PointInACircle(UnityRandom.Normalization.STDNORMAL, 5.0f)@
132 | * A random *Vector2* point in a disk (in the circle *area*) with R=1: @Vector2 pos = urand.PointInADisk()@
133 | * A random *Vector2* point in a circle (in the circle *area*) with R=1 *normalized*: @Vector2 pos = urand.PointInADisk(UnityRandom.Normalization.STDNORMAL, 5.0f)@
134 |
135 | h4. Vector3
136 |
137 | generation of Unity Vector3
138 |
139 | h5. Cube
140 |
141 | * A random *Vector3* point inside a cube with L=1: @Vector3 pos = urand.PointInACube()@
142 | * A random *Vector3* point inside a cube with L=1 *normalized*: @Vector3 pos = urand.PointInACube(UnityRandom.Normalization.STDNORMAL, 5.0f)@
143 | * A random *Vector3* point in the surface of a cube with L=1: @Vector3 pos = urand.PointOnACube()@
144 | * A random *Vector3* point inside a cube with L=1 *normalized*: @Vector3 pos = urand.PointOnACube(UnityRandom.Normalization.STDNORMAL, 5.0f)@
145 |
146 | h5. Sphere
147 |
148 | * A random *Vector3* point inside a sphere (in the sphere *volume*) with R=1: @Vector3 pos = urand.PointInASphere()@
149 | * A random *Vector3* point in the sphere surface (in the sphere *surface*) with R=1: @Vector3 pos = urand.PointOnASphere()@
150 |
151 | h4. Color
152 |
153 | * A random *Color* in the range of visible light (rainbow): @Color col = urand.Rainbow()@
154 | * A random *Color* in the range of visible light (rainbow) *normalized*: @Color col = urand.Rainbow(UnityRandom.Normalization.STDNORMAL, 5.0f)@
155 |
156 | h4. Dice
157 |
158 | * A *Dice Roll*: @DiceRoll roll = urand.RollDice(n,type)@
159 |
160 | *Dice types:*
161 |
162 | * DiceRoll.DiceType.D2
163 | * DiceRoll.DiceType.D3
164 | * DiceRoll.DiceType.D4
165 | * DiceRoll.DiceType.D6
166 | * DiceRoll.DiceType.D8
167 | * DiceRoll.DiceType.D10
168 | * DiceRoll.DiceType.D12
169 | * DiceRoll.DiceType.D20
170 | * DiceRoll.DiceType.D30
171 | * DiceRoll.DiceType.D100
172 |
173 | Example 2D6:
174 |
175 | @DiceRoll roll = urand.RollDice(2,DiceRoll.DiceType.D6)@
176 |
177 | h4. Shuffle Bag
178 |
179 | From: http://kaioa.com/node/53
180 |
181 | In games or educational programs you often don't want real randomness. Unsurprisingly random it's often a bit too random. You may get some items several times in a row and others too rarely. It's either too easy or too hard. Balancing the weights is hard as well, because each run is too different. And if that wouldn't be already bad enough; it's also difficult to verify the results.
182 |
183 | A shuffle Bag with values: [1,10]
184 |
185 | @float[] shufflebag = {1,2,3,4,5,6,7,8,9,10};@
186 |
187 | @ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag);@
188 |
189 | @float randvalue = thebag.Next()@
190 |
191 | A shuffle bag with weighted values:
192 |
193 | @Dictionary wshufflebag = new Dictionary();@
194 |
195 | @wshufflebag[1] = 5;@
196 |
197 | @wshufflebag[2] = 45;@
198 |
199 | @wshufflebag[3] = 25;@
200 |
201 | @wshufflebag[4] = 25;@
202 |
203 | @ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag); @
204 |
205 | @float randvalue = thebag.Next()@
206 |
207 |
208 |
209 |
210 |
211 | h3. Dev Notes
212 |
213 | * *Clone and test*
214 | ** Fork the main project or clone: git://github.com/tucano/UnityRandom.git
215 | ** Create an empty project in Unity
216 | ** cd ./Assets
217 | ** clone the repo there!
218 |
219 |
--------------------------------------------------------------------------------
/Editor/UnityRandomEditorWindow.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | using System;
5 | using System.Collections;
6 | using System.Collections.Generic;
7 | using System.Text;
8 | using System.IO;
9 |
10 | using URandom;
11 |
12 | public class UnityRandomEditorWindow : EditorWindow {
13 |
14 | #region Attributes
15 |
16 | float[] shufflebag = {1,2,3,4,5,6,7,8,9,10};
17 | Dictionary wshufflebag;
18 |
19 | float alpha = 0;
20 | float beta = 0;
21 | bool rotation = false;
22 |
23 | int _graph_area_width = 500;
24 | int _graph_area_height = 500;
25 | int _area_margin = 10;
26 | int _editor_area_width = 400;
27 | int _editor_area_height = 400;
28 |
29 | int _range_min = 0;
30 | int _range_max = Int32.MaxValue;
31 |
32 | bool transform = false;
33 | int samplig_size = 500;
34 | int max_samplig_size = 10000; // depend on the type
35 | float temperature = 5.0f;
36 |
37 | int seed;
38 | string stringSeed = Int32.MaxValue.ToString();
39 |
40 | // FOR CAP AND RING
41 | float spotAngle = 20.0f;
42 | float innerAngle = 20.0f;
43 | float outerAngle = 60.0f;
44 | ArrayList randomList;
45 | String filename = "sampling.txt";
46 | private String path;
47 | StreamWriter fileWriter = null;
48 |
49 | // GENERAL TYPE
50 | public enum RandomType
51 | {
52 | NUMBER = 1,
53 | VECTOR_2D = 2,
54 | VECTOR_3D = 3,
55 | COLOR = 4,
56 | DICE = 5,
57 | SHUFFLEBAG = 6,
58 | WEIGHTEDBAG = 7
59 | }
60 | private RandomType _randomType = RandomType.NUMBER;
61 |
62 | // TYPE OF RANDOM FLOAT NUMBER
63 | public enum RandomNumberType
64 | {
65 | VALUE = 0,
66 | RANGE = 1,
67 | POISSON = 2,
68 | EXPONENTIAL = 3,
69 | GAMMA = 4
70 | }
71 | private RandomNumberType _randomNumberType = RandomNumberType.VALUE;
72 |
73 | // TYPE OF RANDOM VECTOR 2D
74 | public enum RandomVector2DType
75 | {
76 | SQUARE = 0,
77 | CIRCLE = 1,
78 | DISK = 2
79 | }
80 | private RandomVector2DType _randomVector2DType = RandomVector2DType.SQUARE;
81 |
82 | // TYPE OF RANDOM VECTOR 3D
83 | public enum RandomVector3DType
84 | {
85 | INCUBE = 0,
86 | ONCUBE = 1,
87 | INSPHERE = 2,
88 | ONSPHERE = 3,
89 | ONCAP = 4,
90 | ONRING = 5
91 | }
92 | private RandomVector3DType _randomVector3DType = RandomVector3DType.ONSPHERE;
93 |
94 | // THIS IS THE NORMALIZATION FOR UnityRandom Class
95 | private UnityRandom.Normalization normalization = UnityRandom.Normalization.STDNORMAL;
96 |
97 | // THIS IS THE DICE TYPE
98 | private DiceRoll.DiceType dice = DiceRoll.DiceType.D6;
99 | private int nroll = 1;
100 |
101 | #endregion
102 |
103 |
104 | #region Init,Update,OnGUI
105 | // Add menu named "Unity Random" to the Window menu
106 | [MenuItem ("Window/Unity Random")]
107 | static void Init ()
108 | {
109 | // Get existing open window or if none, make a new one:
110 | UnityRandomEditorWindow window = (UnityRandomEditorWindow)EditorWindow.GetWindow(typeof (UnityRandomEditorWindow), false, "UNITY RANDOM");
111 | window.Show();
112 | }
113 |
114 | // Update
115 | void Update()
116 | {
117 | if (rotation)
118 | {
119 | // NAIF ROTATION
120 | alpha += Time.deltaTime * 500;
121 | beta += Time.deltaTime * 500;
122 | this.Repaint();
123 | }
124 | }
125 |
126 | // OnGUI
127 | void OnGUI()
128 | {
129 | // SAMPLING SIZE
130 | switch (_randomType) {
131 | case RandomType.NUMBER: max_samplig_size = 10000; break;
132 | case RandomType.VECTOR_2D: max_samplig_size = 5000; break;
133 | case RandomType.VECTOR_3D: max_samplig_size = 1000; break;
134 | case RandomType.COLOR: max_samplig_size = 400; break;
135 | case RandomType.DICE: max_samplig_size = 5000; break;
136 | default: max_samplig_size = 5000; break;
137 | }
138 | // ADJUST CURRENT SIZE
139 | if (samplig_size > max_samplig_size) samplig_size = max_samplig_size;
140 |
141 | // DRAWING AREA
142 | GUILayout.BeginArea(new Rect(_area_margin,_area_margin,_graph_area_width, _graph_area_height));
143 | GUILayout.Box("", GUILayout.Width(_graph_area_width), GUILayout.Height(_graph_area_height));
144 | if (randomList != null && randomList.Count > 0) {
145 | switch (_randomType) {
146 | case RandomType.NUMBER:
147 | switch (_randomNumberType) {
148 | case RandomNumberType.VALUE:
149 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height);
150 | break;
151 | case RandomNumberType.RANGE:
152 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, _range_min, _range_max);
153 | break;
154 | default:
155 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, true);
156 | break;
157 | }
158 | break;
159 | case RandomType.VECTOR_2D:
160 | UnityRandomEditorDraw.DrawV2Plot(randomList, _graph_area_width, _graph_area_height, _randomVector2DType);
161 | break;
162 | case RandomType.VECTOR_3D:
163 | UnityRandomEditorDraw.DrawV3Plot(randomList, _graph_area_width, _graph_area_height, _randomVector3DType, alpha, beta);
164 | break;
165 | case RandomType.COLOR:
166 | UnityRandomEditorDraw.DrawColorPlot(randomList, _graph_area_width, _graph_area_height);
167 | break;
168 | case RandomType.DICE:
169 | // generate a new ArrayList with the Sum, then send to DrawXYPlot
170 | ArrayList sums = RandomDiceSums();
171 | sums.Sort();
172 | UnityRandomEditorDraw.DrawXYPlot(sums, _graph_area_width, _graph_area_height, true);
173 | break;
174 | case RandomType.SHUFFLEBAG:
175 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, shufflebag[0], shufflebag[shufflebag.Length - 1]);
176 | break;
177 | case RandomType.WEIGHTEDBAG:
178 | UnityRandomEditorDraw.DrawXYPlot(randomList, _graph_area_width, _graph_area_height, 1, 10);
179 | break;
180 | default:
181 | // defailt is no drawing
182 | break;
183 | }
184 | }
185 | GUILayout.EndArea();
186 |
187 | // SAMPLE RANDOM BUTTON
188 | GUILayout.BeginArea(new Rect(_area_margin, _area_margin + _area_margin + _graph_area_height, _graph_area_width, 60));
189 | EditorGUILayout.BeginHorizontal();
190 | if (GUILayout.Button("Generate Random Numbers",GUILayout.Height(60))) {
191 | this.SampleRandom();
192 | }
193 | EditorGUILayout.EndHorizontal();
194 | GUILayout.EndArea();
195 |
196 | // CONTROL PANEL RIGHT BOX
197 | GUILayout.BeginArea(new Rect(_area_margin + _area_margin +_graph_area_width, _area_margin, _editor_area_width, _editor_area_height));
198 |
199 | // TITLE
200 | EditorGUILayout.BeginVertical("box");
201 | EditorGUILayout.BeginHorizontal();
202 | GUILayout.FlexibleSpace();
203 | GUILayout.Label("CHOOSE TYPE OF RANDOM TYPE: ");
204 | _randomType = (RandomType) EditorGUILayout.EnumPopup(_randomType, GUILayout.Width(100));
205 | GUILayout.FlexibleSpace();
206 | EditorGUILayout.EndHorizontal();
207 | EditorGUILayout.EndVertical();
208 |
209 | switch (_randomType) {
210 |
211 | case RandomType.NUMBER: RandomNumbersGUI();
212 | break;
213 |
214 | case RandomType.VECTOR_2D: RandomVector2DGUI();
215 | break;
216 |
217 | case RandomType.VECTOR_3D: RandomVector3DGUI();
218 | break;
219 |
220 | case RandomType.COLOR: RandomColorGUI();
221 | break;
222 |
223 | case RandomType.DICE: RandomDiceGUI();
224 | break;
225 |
226 | case RandomType.SHUFFLEBAG: ShuffleBagGUI();
227 | break;
228 |
229 | case RandomType.WEIGHTEDBAG: ShuffleBagGUI();
230 | break;
231 |
232 | default:
233 | break;
234 | }
235 |
236 | EditorGUILayout.BeginVertical("box");
237 | samplig_size = EditorGUILayout.IntSlider ("Sampling Size:", samplig_size, 1, max_samplig_size);
238 | EditorGUILayout.EndVertical();
239 |
240 | if (randomList != null && randomList.Count > 0) {
241 | EditorGUILayout.BeginVertical("box");
242 | EditorGUILayout.BeginHorizontal();
243 | GUILayout.FlexibleSpace();
244 | if (GUILayout.Button("SAVE",GUILayout.Width(100))) this.Save();
245 | GUILayout.FlexibleSpace();
246 | filename = EditorGUILayout.TextField(filename);
247 | EditorGUILayout.EndHorizontal();
248 | EditorGUILayout.EndVertical();
249 | }
250 |
251 |
252 | // 3D VIEWS BUTTONS
253 | if (randomList != null && randomList.Count > 0 && _randomType == RandomType.VECTOR_3D &&
254 | (_randomVector3DType == RandomVector3DType.INSPHERE ||
255 | _randomVector3DType == RandomVector3DType.ONSPHERE ||
256 | _randomVector3DType == RandomVector3DType.ONCAP ||
257 | _randomVector3DType == RandomVector3DType.ONRING )) {
258 | EditorGUILayout.BeginVertical("box");
259 | String rotationLabel = rotation ? "STOP ROTATE VIEW" : "START ROTATE VIEW";
260 | if (GUILayout.Button(rotationLabel,GUILayout.Height(60))) {
261 | rotation = !rotation;
262 | }
263 | EditorGUILayout.EndVertical();
264 | }
265 | GUILayout.EndArea();
266 |
267 | // if GUI has changed empty the Array
268 | if (GUI.changed && randomList != null && randomList.Count != 0) {
269 | CleanList();
270 | this.Repaint();
271 | }
272 |
273 | // if Array is empty stop rotation and reset alpha/beta
274 | if (randomList == null || randomList.Count == 0) {
275 | rotation = false;
276 | alpha = beta = 0;
277 | }
278 | }
279 |
280 | #endregion
281 |
282 | #region PrivateMethods
283 | private void CleanList()
284 | {
285 | // FIXME I NEED TO REMOVE OBJECTS MANUALLY?
286 | randomList.Clear();
287 | }
288 |
289 | private ArrayList RandomDiceSums()
290 | {
291 | ArrayList result = new ArrayList();
292 | foreach ( object obj in randomList )
293 | {
294 | DiceRoll _roll = (DiceRoll) obj;
295 | result.Add( _roll.Sum() );
296 | }
297 | return result;
298 | }
299 |
300 | // DICES GUI
301 | private void RandomDiceGUI()
302 | {
303 | EditorGUILayout.BeginVertical("box");
304 | EditorGUILayout.BeginHorizontal();
305 | GUILayout.FlexibleSpace();
306 | GUILayout.Label("TEST RANDOM DICES");
307 | GUILayout.FlexibleSpace();
308 | EditorGUILayout.EndHorizontal();
309 | EditorGUILayout.EndVertical();
310 |
311 | SeedBoxGUI();
312 |
313 | EditorGUILayout.BeginVertical("box");
314 | EditorGUILayout.BeginHorizontal();
315 | GUILayout.Label("Dice:", GUILayout.Width(100));
316 | dice = (DiceRoll.DiceType) EditorGUILayout.EnumPopup(dice, GUILayout.Width(100));
317 | GUILayout.FlexibleSpace();
318 | GUILayout.Label( (nroll + dice.ToString()), GUILayout.Width(100));
319 | EditorGUILayout.EndHorizontal();
320 | EditorGUILayout.EndVertical();
321 |
322 | EditorGUILayout.BeginVertical("box");
323 | EditorGUILayout.BeginHorizontal();
324 | GUILayout.Label("#Rolls:", GUILayout.Width(100));
325 | nroll = EditorGUILayout.IntSlider(nroll, 0, 10);
326 | GUILayout.FlexibleSpace();
327 | EditorGUILayout.EndHorizontal();
328 | EditorGUILayout.EndVertical();
329 | }
330 |
331 | // BOXSEEDCONFIGURATION
332 | private void SeedBoxGUI()
333 | {
334 | EditorGUILayout.BeginVertical("box");
335 | EditorGUILayout.BeginHorizontal();
336 | GUILayout.Label("RandomSeed:", GUILayout.Width(100));
337 | stringSeed = EditorGUILayout.TextField(stringSeed, GUILayout.Width(100));
338 | ParseSeed();
339 | GUILayout.FlexibleSpace();
340 | GUILayout.Label("range: +/-" + Int32.MaxValue);
341 | EditorGUILayout.EndHorizontal();
342 | EditorGUILayout.EndVertical();
343 | }
344 |
345 | private void ShuffleBagGUI()
346 | {
347 | EditorGUILayout.BeginVertical("box");
348 | EditorGUILayout.BeginHorizontal();
349 | GUILayout.FlexibleSpace();
350 | GUILayout.Label("TEST SHUFFLE BAG");
351 | GUILayout.FlexibleSpace();
352 | EditorGUILayout.EndHorizontal();
353 | EditorGUILayout.EndVertical();
354 | SeedBoxGUI();
355 | }
356 |
357 | private void RandomColorGUI()
358 | {
359 | EditorGUILayout.BeginVertical("box");
360 | EditorGUILayout.BeginHorizontal();
361 | GUILayout.FlexibleSpace();
362 | GUILayout.Label("TEST RANDOM COLORS");
363 | GUILayout.FlexibleSpace();
364 | EditorGUILayout.EndHorizontal();
365 | EditorGUILayout.EndVertical();
366 | SeedBoxGUI();
367 |
368 | // BOX TRANSFORMATIONS
369 | EditorGUILayout.BeginVertical("box");
370 | EditorGUILayout.BeginHorizontal();
371 | GUILayout.FlexibleSpace();
372 | GUILayout.Label("TRANSFORMATIONS");
373 | GUILayout.FlexibleSpace();
374 | EditorGUILayout.EndHorizontal();
375 | EditorGUILayout.EndVertical();
376 |
377 | EditorGUILayout.BeginVertical("box");
378 | transform = EditorGUILayout.Toggle("Transform?",transform);
379 | EditorGUILayout.EndVertical();
380 |
381 | if (transform) NormalizationNumberTypes();
382 | }
383 |
384 | private void RandomVector3DGUI()
385 | {
386 | EditorGUILayout.BeginVertical("box");
387 | EditorGUILayout.BeginHorizontal();
388 | GUILayout.FlexibleSpace();
389 | GUILayout.Label("TEST RANDOM VECTOR3");
390 | GUILayout.FlexibleSpace();
391 | EditorGUILayout.EndHorizontal();
392 | EditorGUILayout.EndVertical();
393 |
394 | EditorGUILayout.BeginVertical("box");
395 | EditorGUILayout.BeginHorizontal();
396 | GUILayout.Label("Random Type:", GUILayout.Width(100));
397 | _randomVector3DType = (RandomVector3DType) EditorGUILayout.EnumPopup(_randomVector3DType, GUILayout.Width(100));
398 | GUILayout.FlexibleSpace();
399 | switch (_randomVector3DType) {
400 | case RandomVector3DType.INCUBE:
401 | case RandomVector3DType.ONCUBE:
402 | GUILayout.Label("Vector3: [-1,1] r = 1");
403 | break;
404 | case RandomVector3DType.ONSPHERE:
405 | case RandomVector3DType.INSPHERE:
406 | case RandomVector3DType.ONCAP:
407 | case RandomVector3DType.ONRING:
408 | GUILayout.Label("Vector3: [-1,1] r = 1");
409 | break;
410 | default:
411 | break;
412 | }
413 | EditorGUILayout.EndHorizontal();
414 |
415 | switch (_randomVector3DType) {
416 | case RandomVector3DType.ONCAP:
417 | spotAngle = EditorGUILayout.Slider ("Spot Angle:", spotAngle, 0.0f, 180.0f);
418 | break;
419 | case RandomVector3DType.ONRING:
420 | innerAngle = EditorGUILayout.Slider ("Inner Angle:", innerAngle, 0.0f, 180.0f);
421 | outerAngle = EditorGUILayout.Slider ("Outer Angle:", outerAngle, 0.0f, 180.0f);
422 | if (innerAngle > outerAngle) innerAngle = outerAngle;
423 | break;
424 | default:
425 | break;
426 | }
427 |
428 | EditorGUILayout.EndVertical();
429 |
430 | SeedBoxGUI();
431 |
432 | // BOX TRANSFORMATIONS
433 | EditorGUILayout.BeginVertical("box");
434 | EditorGUILayout.BeginHorizontal();
435 | GUILayout.FlexibleSpace();
436 | GUILayout.Label("TRANSFORMATIONS");
437 | GUILayout.FlexibleSpace();
438 | EditorGUILayout.EndHorizontal();
439 | EditorGUILayout.EndVertical();
440 |
441 | EditorGUILayout.BeginVertical("box");
442 | transform = EditorGUILayout.Toggle("Transform?",transform);
443 | EditorGUILayout.EndVertical();
444 |
445 | if (transform) NormalizationNumberTypes();
446 | }
447 |
448 | private void RandomVector2DGUI()
449 | {
450 | EditorGUILayout.BeginVertical("box");
451 | EditorGUILayout.BeginHorizontal();
452 | GUILayout.FlexibleSpace();
453 | GUILayout.Label("TEST RANDOM VECTOR2");
454 | GUILayout.FlexibleSpace();
455 | EditorGUILayout.EndHorizontal();
456 | EditorGUILayout.EndVertical();
457 |
458 | EditorGUILayout.BeginVertical("box");
459 | // TYPE
460 | EditorGUILayout.BeginHorizontal();
461 | GUILayout.Label("Random Type:", GUILayout.Width(100));
462 | _randomVector2DType = (RandomVector2DType) EditorGUILayout.EnumPopup(_randomVector2DType, GUILayout.Width(100));
463 | GUILayout.FlexibleSpace();
464 | switch (_randomVector2DType) {
465 | case RandomVector2DType.SQUARE:
466 | GUILayout.Label("Vector2: [-1,1]");
467 | break;
468 | case RandomVector2DType.CIRCLE:
469 | GUILayout.Label("Vector2: [-1,1] r = 1");
470 | break;
471 | case RandomVector2DType.DISK:
472 | GUILayout.Label("Vector2: [-1,1] r = 1");
473 | break;
474 | default:
475 | break;
476 | }
477 | EditorGUILayout.EndHorizontal();
478 | EditorGUILayout.EndVertical();
479 |
480 | SeedBoxGUI();
481 |
482 | // BOX TRANSFORMATIONS
483 | EditorGUILayout.BeginVertical("box");
484 | EditorGUILayout.BeginHorizontal();
485 | GUILayout.FlexibleSpace();
486 | GUILayout.Label("TRANSFORMATIONS");
487 | GUILayout.FlexibleSpace();
488 | EditorGUILayout.EndHorizontal();
489 | EditorGUILayout.EndVertical();
490 |
491 | EditorGUILayout.BeginVertical("box");
492 | transform = EditorGUILayout.Toggle("Transform?",transform);
493 | EditorGUILayout.EndVertical();
494 |
495 | if (transform) NormalizationNumberTypes();
496 | }
497 |
498 | private void RandomNumbersGUI()
499 | {
500 | EditorGUILayout.BeginVertical("box");
501 | EditorGUILayout.BeginHorizontal();
502 | GUILayout.FlexibleSpace();
503 | GUILayout.Label("TEST RANDOM NUMBERS");
504 | GUILayout.FlexibleSpace();
505 | EditorGUILayout.EndHorizontal();
506 | EditorGUILayout.EndVertical();
507 |
508 |
509 | // BOX RANDOM NUMBER CONFIGURATION
510 | EditorGUILayout.BeginVertical("box");
511 | // TYPE
512 | EditorGUILayout.BeginHorizontal();
513 | GUILayout.Label("Random Type:", GUILayout.Width(100));
514 | _randomNumberType = (RandomNumberType) EditorGUILayout.EnumPopup( _randomNumberType, GUILayout.Width(100));
515 | // HELP TYPE
516 | GUILayout.FlexibleSpace();
517 | if (_randomNumberType == RandomNumberType.VALUE) {
518 | GUILayout.Label("Float: 0 < x < 1");
519 | } else {
520 | GUILayout.Label("Float: 0 < x < " + Int32.MaxValue);
521 | }
522 | EditorGUILayout.EndHorizontal();
523 | EditorGUILayout.EndVertical();
524 |
525 | // RANGES SLIDERS
526 | if (_randomNumberType == RandomNumberType.RANGE)
527 | {
528 | EditorGUILayout.BeginVertical("box");
529 | GUILayout.Label("Any Int Number in range: 0 - " + Int32.MaxValue + ". Test range: 0 - 100");
530 | EditorGUILayout.BeginHorizontal();
531 | GUILayout.BeginVertical();
532 | GUILayout.Label("Min:");
533 | GUILayout.Label("Max:");
534 | GUILayout.EndVertical();
535 | GUILayout.BeginVertical();
536 | _range_min = EditorGUILayout.IntSlider(_range_min, 0, 100, GUILayout.ExpandWidth(true));
537 | _range_max = EditorGUILayout.IntSlider(_range_max, 0, 100, GUILayout.ExpandWidth(true));
538 | if (_range_min > _range_max) _range_max = _range_min;
539 | GUILayout.EndVertical();
540 | EditorGUILayout.EndHorizontal();
541 | EditorGUILayout.EndVertical();
542 | }
543 |
544 | SeedBoxGUI();
545 |
546 | // BOX TRANSFORMATIONS
547 | switch (_randomNumberType) {
548 | case RandomNumberType.VALUE:
549 | case RandomNumberType.RANGE:
550 | EditorGUILayout.BeginVertical("box");
551 | EditorGUILayout.BeginHorizontal();
552 | GUILayout.FlexibleSpace();
553 | GUILayout.Label("TRANSFORMATIONS");
554 | GUILayout.FlexibleSpace();
555 | EditorGUILayout.EndHorizontal();
556 | EditorGUILayout.EndVertical();
557 |
558 | EditorGUILayout.BeginVertical("box");
559 | transform = EditorGUILayout.Toggle("Transform?",transform);
560 | EditorGUILayout.EndVertical();
561 |
562 | if (transform) NormalizationNumberTypes();
563 | break;
564 |
565 | case RandomNumberType.POISSON:
566 | EditorGUILayout.BeginVertical("box");
567 | temperature = EditorGUILayout.Slider ("Lambda", temperature, 0.0f, 100.0f);
568 | EditorGUILayout.EndVertical();
569 | break;
570 |
571 | case RandomNumberType.EXPONENTIAL:
572 | EditorGUILayout.BeginVertical("box");
573 | temperature = EditorGUILayout.Slider ("Lambda", temperature, 0.0f, 10.0f);
574 | EditorGUILayout.EndVertical();
575 | break;
576 |
577 | case RandomNumberType.GAMMA:
578 | EditorGUILayout.BeginVertical("box");
579 | temperature = (float) EditorGUILayout.IntSlider ("Integer Order", (int) temperature, 0, 100);
580 | EditorGUILayout.EndVertical();
581 | break;
582 |
583 | default:
584 | break;
585 | }
586 | }
587 |
588 | private void NormalizationNumberTypes()
589 | {
590 | EditorGUILayout.BeginVertical("box");
591 |
592 | EditorGUILayout.BeginHorizontal();
593 | GUILayout.Label("Tranformation Type:");
594 | normalization = (UnityRandom.Normalization) EditorGUILayout.EnumPopup( normalization, GUILayout.Width(100.0f));
595 | EditorGUILayout.EndHorizontal();
596 |
597 | switch (normalization) {
598 |
599 | case UnityRandom.Normalization.STDNORMAL:
600 | temperature = EditorGUILayout.Slider ("Temperature", temperature, 0.0f, 10.0f);
601 | break;
602 |
603 | case UnityRandom.Normalization.POWERLAW:
604 | temperature = EditorGUILayout.Slider ("Power", temperature, 0.0f, 100.0f);
605 | break;
606 |
607 | default:
608 | Debug.LogError("Unrecognized Option");
609 | break;
610 | }
611 | EditorGUILayout.EndVertical();
612 | }
613 |
614 | private void SampleRandom()
615 | {
616 | Debug.Log("GENERATING RANDOM " + _randomType + " WITH SEED: " + seed);
617 |
618 | UnityRandom urand = new UnityRandom(seed);
619 | if (randomList == null) randomList = new ArrayList();
620 | randomList.Clear();
621 |
622 | switch (_randomType)
623 | {
624 | case RandomType.NUMBER: SampleNumber(ref urand); break;
625 | case RandomType.VECTOR_2D: SampleVector2D(ref urand); break;
626 | case RandomType.VECTOR_3D: SampleVector3D(ref urand); break;
627 | case RandomType.COLOR: SampleColor(ref urand); break;
628 | case RandomType.DICE: SampleDice(ref urand); break;
629 | case RandomType.SHUFFLEBAG: SampleShuffle(ref urand); break;
630 | case RandomType.WEIGHTEDBAG: SampleWShuffle(ref urand); break;
631 | default: SampleNumber(ref urand); break;
632 | }
633 |
634 | this.Repaint();
635 | }
636 |
637 | private void SampleShuffle(ref UnityRandom _urand)
638 | {
639 | ShuffleBagCollection thebag = _urand.ShuffleBag(shufflebag);
640 | for (int m = 0; m < samplig_size; m++)
641 | {
642 | randomList.Add(thebag.Next());
643 | }
644 | randomList.Sort();
645 | }
646 |
647 | // Really no time to make it better (FIXME)
648 | private void SampleWShuffle(ref UnityRandom _urand)
649 | {
650 | wshufflebag = new Dictionary();
651 | // fill the wshufflebag
652 | wshufflebag[1] = 5;
653 | wshufflebag[2] = 10;
654 | wshufflebag[3] = 10;
655 | wshufflebag[4] = 25;
656 | wshufflebag[5] = 25;
657 | wshufflebag[6] = 10;
658 | wshufflebag[7] = 5;
659 | wshufflebag[8] = 5;
660 | wshufflebag[9] = 3;
661 | wshufflebag[10] = 2;
662 |
663 | ShuffleBagCollection thebag = _urand.ShuffleBag(wshufflebag);
664 | for (int m = 0; m < samplig_size; m++)
665 | {
666 | randomList.Add(thebag.Next());
667 | }
668 | randomList.Sort();
669 | }
670 |
671 | private void SampleDice(ref UnityRandom _urand)
672 | {
673 | for (int i = 0; i < samplig_size; i++)
674 | {
675 | randomList.Add( _urand.RollDice(nroll, dice));
676 | }
677 | }
678 |
679 | private void SampleColor(ref UnityRandom _urand)
680 | {
681 | for (int i = 0; i < samplig_size; i++)
682 | {
683 | if (transform) {
684 | randomList.Add(_urand.Rainbow(normalization,temperature));
685 | } else {
686 | randomList.Add(_urand.Rainbow());
687 | }
688 | }
689 | }
690 |
691 | private void SampleVector3D(ref UnityRandom _urand)
692 | {
693 | for (int i = 0; i < samplig_size; i++)
694 | {
695 | switch (_randomVector3DType) {
696 | case RandomVector3DType.INCUBE:
697 | if (transform) {
698 | randomList.Add(_urand.PointInACube(normalization,temperature));
699 | } else {
700 | randomList.Add(_urand.PointInACube());
701 | }
702 | break;
703 | case RandomVector3DType.ONCUBE:
704 | if (transform) {
705 | randomList.Add(_urand.PointOnACube(normalization,temperature));
706 | } else {
707 | randomList.Add(_urand.PointOnACube());
708 | }
709 | break;
710 | case RandomVector3DType.INSPHERE:
711 | randomList.Add(_urand.PointInASphere());
712 | break;
713 | case RandomVector3DType.ONSPHERE:
714 | randomList.Add(_urand.PointOnASphere());
715 | break;
716 | case RandomVector3DType.ONCAP:
717 | randomList.Add(_urand.PointOnCap(spotAngle));
718 | break;
719 | case RandomVector3DType.ONRING:
720 | randomList.Add(_urand.PointOnRing(innerAngle,outerAngle));
721 | break;
722 | default:
723 | break;
724 | }
725 | }
726 | }
727 |
728 | private void SampleVector2D(ref UnityRandom _urand)
729 | {
730 | for (int i = 0; i < samplig_size; i++)
731 | {
732 | switch (_randomVector2DType) {
733 | case RandomVector2DType.SQUARE:
734 | if (transform) {
735 | randomList.Add(_urand.PointInASquare(normalization,temperature));
736 | } else {
737 | randomList.Add(_urand.PointInASquare());
738 | }
739 | break;
740 | case RandomVector2DType.CIRCLE:
741 | if (transform) {
742 | randomList.Add(_urand.PointInACircle(normalization,temperature));
743 | } else {
744 | randomList.Add(_urand.PointInACircle());
745 | }
746 | break;
747 | case RandomVector2DType.DISK:
748 | if (transform) {
749 | randomList.Add(_urand.PointInADisk(normalization,temperature));
750 | } else {
751 | randomList.Add(_urand.PointInADisk());
752 | }
753 | break;
754 | default:
755 | break;
756 | }
757 | }
758 | }
759 |
760 | private void SampleNumber(ref UnityRandom _urand)
761 | {
762 | for (int i = 0; i < samplig_size; i++)
763 | {
764 | switch (_randomNumberType) {
765 |
766 | case RandomNumberType.VALUE:
767 | if (transform) {
768 | randomList.Add(_urand.Value( normalization, temperature ));
769 | } else {
770 | randomList.Add(_urand.Value());
771 | }
772 | break;
773 |
774 | case RandomNumberType.RANGE:
775 | if (transform) {
776 | randomList.Add(_urand.Range(_range_min, _range_max, normalization, temperature ));
777 | } else {
778 | randomList.Add(_urand.Range(_range_min, _range_max));
779 | }
780 | break;
781 |
782 |
783 | case RandomNumberType.POISSON:
784 | randomList.Add(_urand.Possion(temperature));
785 | break;
786 |
787 | case RandomNumberType.EXPONENTIAL:
788 | randomList.Add(_urand.Exponential(temperature));
789 | break;
790 |
791 | case RandomNumberType.GAMMA:
792 | randomList.Add(_urand.Gamma(temperature));
793 | break;
794 |
795 | default:
796 | break;
797 | }
798 | }
799 | randomList.Sort();
800 | }
801 |
802 | private void Save()
803 | {
804 | path = Application.dataPath + "/UnityRandom/Samples/" + filename;
805 | Debug.Log("SAVING TO FILE: " + path);
806 |
807 | fileWriter = File.CreateText(path);
808 |
809 | foreach ( object obj in randomList )
810 | {
811 | // FIXME SAMPLING WRITE LINE FOR Vector3 and Vector2
812 | switch (_randomType)
813 | {
814 | case RandomType.NUMBER:
815 | fileWriter.WriteLine(obj);
816 | break;
817 | case RandomType.VECTOR_2D:
818 | Vector2 pos = (Vector2) obj;
819 | fileWriter.WriteLine(pos.x + "\t" + pos.y);
820 | break;
821 | case RandomType.VECTOR_3D:
822 | Vector3 pos3 = (Vector3) obj;
823 | fileWriter.WriteLine(pos3.x + "\t" + pos3.y + "\t" + pos3.z);
824 | break;
825 | default:
826 | break;
827 | }
828 |
829 | }
830 |
831 | // when you are done writing
832 | fileWriter.Close();
833 |
834 | UnityEngine.Object myfile = AssetDatabase.LoadMainAssetAtPath("Assets/UnityRandom/Samples/" + filename);
835 | AssetDatabase.OpenAsset(myfile);
836 | }
837 |
838 | private void ParseSeed()
839 | {
840 | checked
841 | {
842 | try
843 | {
844 | seed = int.Parse(stringSeed);
845 | }
846 | catch (System.Exception)
847 | {
848 | seed = Int32.MaxValue;
849 | stringSeed = seed.ToString();
850 | this.Repaint();
851 | }
852 | }
853 | }
854 |
855 | #endregion
856 |
857 | #region Events
858 | // BEWARE of TEXTURE2D MEMORY LEAKS!!!!
859 | void OnDisable()
860 | {
861 | // KILL TEXTURES
862 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.tex);
863 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.aaLineTex);
864 | UnityEngine.Object.DestroyImmediate(UnityRandomEditorDraw.lineTex);
865 | }
866 | #endregion
867 | }
868 |
--------------------------------------------------------------------------------