/// <summary> /// Create a ForcedRandomSeries with the given sample sequence and the seed as offset. /// The sequence is supposed to contain NxN points in random order. /// </summary> public ForcedRandomSeries(V2i[] series, int matrixSize, IRandomUniform rnd, bool jitter = true) { m_series = series; m_matrixSize = matrixSize; m_norm = 1.0 / m_matrixSize; // [0, 1) m_rnd = rnd; m_jitter = jitter; // random offset of sample pattern m_seed = new V2i(rnd.UniformInt(m_matrixSize), rnd.UniformInt(m_matrixSize)); }
/// <summary> /// Returns a uniformly distributed double in the closed interval /// [0.0, 1.0]. Note, that two random values are used to make all 53 /// bits random. /// </summary> public static double UniformDoubleFullClosed(this IRandomUniform rnd) { if (rnd.GeneratesFullDoubles) { return(rnd.UniformDoubleClosed()); } long r = ((~0xfL & (long)rnd.UniformInt()) << 22) | ((long)rnd.UniformInt() >> 5); return(r * (1.0 / 9007199254740991.0)); }
/// <summary> /// Returns a uniformly distributed double in the open interval /// (0.0, 1.0). Note, that two random values are used to make all 53 /// bits random. /// </summary> public static double UniformDoubleFullOpen(this IRandomUniform rnd) { if (rnd.GeneratesFullDoubles) { return(rnd.UniformDoubleOpen()); } long r; do { r = ((~0xfL & (long)rnd.UniformInt()) << 22) | ((long)rnd.UniformInt() >> 5); }while (r == 0); return(r * (1.0 / 9007199254740992.0)); }
/// <summary> /// Randomly permute the specified number of elements in the supplied /// list starting at the specified index. /// </summary> public static void Randomize <T>( this IRandomUniform rnd, List <T> list, int start, int count) { for (int i = start; i < start + count; i++) { list.Swap(i, start + rnd.UniformInt(count)); } }
/// <summary> /// Randomly permute the specified number of elements in the supplied /// array starting at the specified index. /// </summary> public static void Randomize <T>( this IRandomUniform rnd, T[] array, int start, int count) { for (int i = start, e = start + count; i < e; i++) { array.Swap(i, start + rnd.UniformInt(count)); } }
/// <summary> /// Fills the specified array with random ints in the interval /// [0, 2^31-1]. /// </summary> public static void FillUniform(this IRandomUniform rnd, int[] array) { long count = array.LongLength; for (long i = 0; i < count; i++) { array[i] = rnd.UniformInt(); } }
/// <summary> /// Randomly permute the elements of the supplied list. /// </summary> public static void Randomize <T>( this IRandomUniform rnd, List <T> list) { int count = list.Count; for (int i = 0; i < count; i++) { list.Swap(i, rnd.UniformInt(count)); } }
/// <summary> /// Returns a uniform int which is guaranteed not to be zero. /// </summary> public static int UniformIntNonZero(this IRandomUniform rnd) { int r; do { r = rnd.UniformInt(); } while (r == 0); return(r); }
/// <summary> /// Creates clusters for all points which are within an epsilon /// distance from each other. This algorithm uses a hash-grid and /// only works fast if the supplied epsilon is small enough that /// not too many points fall within each cluster. Thus it is ideal /// for merging vertices in meshes and point sets, that are different /// due to numerical inaccuracies. /// </summary> public PointEpsilonClustering(V3d[] pa, double epsilon, IRandomUniform rnd = null) { rnd = rnd ?? new RandomSystem(); var count = pa.Length; Alloc(count); var ca = m_indexArray; var dict = new IntDict <int>(count, stackDuplicateKeys: true); int rndBits = 0; int bit = 0; var ha = new int[8]; var eps2 = epsilon * epsilon; for (int i = 0; i < count; i++) { var p = pa[i]; p.HashCodes8(epsilon, ha); int ci = ca[i]; if (ca[ci] != ci) { do { ci = ca[ci]; } while (ca[ci] != ci); ca[i] = ci; } for (int hi = 0; hi < 8; hi++) { foreach (var j in dict.ValuesWithKey(ha[hi])) { int cj = ca[j]; if (ca[cj] != cj) { do { cj = ca[cj]; } while (ca[cj] != cj); ca[j] = cj; } if (ci == cj || V3d.DistanceSquared(p, pa[j]) >= eps2) { continue; } bit >>= 1; if (bit == 0) { rndBits = rnd.UniformInt(); bit = 1 << 30; } if ((rndBits & bit) != 0) { ca[ci] = cj; ca[i] = cj; ci = cj; } else { ca[cj] = ci; ca[j] = ci; } } } dict[ha[0]] = i; } Init(); }
/// <summary> /// Merge clusters of exactly equal points. The supplied epsilon is used to define a /// grid as acceleration data structure and the algorithm is only fast if not too many /// points fall within the supplied epsilon. /// </summary> public PointEqualClustering(V3d[] pa, double eps, IRandomUniform rnd = null) { rnd = rnd ?? new RandomSystem(); var count = pa.Length; Alloc(count); var ca = m_indexArray; var dict = new IntDict <int>(count, stackDuplicateKeys: true); int rndBits = 0; int bit = 0; for (int i = 0; i < count; i++) { var p = pa[i]; var hc = p.HashCode1(eps); int ci = ca[i]; if (ca[ci] != ci) { do { ci = ca[ci]; } while (ca[ci] != ci); ca[i] = ci; } foreach (var j in dict.ValuesWithKey(hc)) { int cj = ca[j]; if (ca[cj] != cj) { do { cj = ca[cj]; } while (ca[cj] != cj); ca[j] = cj; } if (ci == cj || p != pa[j]) { continue; } bit >>= 1; if (bit == 0) { rndBits = rnd.UniformInt(); bit = 1 << 30; } if ((rndBits & bit) != 0) { ca[ci] = cj; ca[i] = cj; ci = cj; } else { ca[cj] = ci; ca[j] = ci; } } dict[hc] = i; } Init(); }
/// <summary> /// Creates an unordered array of subsetCount int indices that /// constitute a subset of all ints in the range [0, count-1]. /// O(subsetCount) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// </summary> public static int[] CreateSmallRandomSubsetIndexArray( this IRandomUniform rnd, int subsetCount, int count) { Requires.That(subsetCount >= 0 && subsetCount <= count); var subsetIndices = new IntSet(subsetCount); for (int i = 0; i < subsetCount; i++) { int index; do { index = rnd.UniformInt(count); }while (!subsetIndices.TryAdd(index)); } return(subsetIndices.ToArray()); }
/// <summary> /// Supply random bits one at a time. The currently unused bits are /// maintained in the supplied reference parameter. Before the first /// call randomBits must be 0. /// </summary> public static bool RandomBit( this IRandomUniform rnd, ref int randomBits) { if (randomBits <= 1) { randomBits = rnd.UniformInt(); bool bit = (randomBits & 1) != 0; randomBits = 0x40000000 | (randomBits >> 1); return(bit); } else { bool bit = (randomBits & 1) != 0; randomBits >>= 1; return(bit); } }
/// <summary> /// Randomly permute the first count elements of the /// supplied array. This does work with counts of up /// to about 2^50. /// </summary> public static void Randomize <T>( this IRandomUniform rnd, T[] array, long count) { if (count <= (long)int.MaxValue) { int intCount = (int)count; for (int i = 0; i < intCount; i++) { array.Swap(i, rnd.UniformInt(intCount)); } } else { for (long i = 0; i < count; i++) { array.Swap(i, rnd.UniformLong(count)); } } }
/// <summary> /// Creates an unordered array of subsetCount int indices that /// constitute a subset of all ints in the range [0, count-1]. /// O(subsetCount) for subsetCount << count. /// NOTE: It is assumed that subsetCount is significantly smaller /// than count. If this is not the case, use /// CreateRandomSubsetOfSize instead. /// WARNING: As subsetCount approaches count execution time /// increases significantly. /// </summary> public static int[] CreateSmallRandomSubsetIndexArray( this IRandomUniform rnd, int subsetCount, int count) { if (!(subsetCount >= 0 && subsetCount <= count)) { throw new ArgumentOutOfRangeException(nameof(subsetCount)); } var subsetIndices = new IntSet(subsetCount); for (int i = 0; i < subsetCount; i++) { int index; do { index = rnd.UniformInt(count); }while (!subsetIndices.TryAdd(index)); } return(subsetIndices.ToArray()); }
/// <summary> /// Creates clusters of planes within a certain epsilon from each other /// (euclidean distance between normal vectors and between offsets). /// This algorithm uses a 4d hash-grid and only works fast if the supplied /// epsilons are small enough that not too many planes fall within each cluster. /// Thus it is ideal for merging planes with small variations in orientation and /// offset due to numerical inaccuracies. /// </summary> public PlaneEpsilonClustering( int count, TArray pa, Func <TArray, int, V3d> getNormal, Func <TArray, int, double> getDist, double epsNormal, double epsDist, double deltaEpsFactor = 0.25, IRandomUniform rnd = null) { rnd = rnd ?? new RandomSystem(); Alloc(count); var ca = m_indexArray; var dict = new IntDict <int>(count, stackDuplicateKeys: true); int rndBits = 0; int bit = 0; var ha = new int[16]; var ne2 = epsNormal * epsNormal; var de2 = epsDist * epsDist; var deps = (ne2 + de2) * deltaEpsFactor * deltaEpsFactor; for (int i = 0; i < count; i++) { var ni = getNormal(pa, i); var di = getDist(pa, i); ni.HashCodes16(di, epsNormal, epsDist, ha); int ci = ca[i]; if (ca[ci] != ci) { do { ci = ca[ci]; } while (ca[ci] != ci); ca[i] = ci; } double dmin = double.MaxValue; for (int hi = 0; hi < 16; hi++) { foreach (var j in dict.ValuesWithKey(ha[hi])) { int cj = ca[j]; if (ca[cj] != cj) { do { cj = ca[cj]; } while (ca[cj] != cj); ca[j] = cj; } if (ci == cj) { continue; } var dd = Fun.Square(di - getDist(pa, j)); if (dd >= de2) { continue; } var dn = V3d.DistanceSquared(ni, getNormal(pa, j)); if (dn >= ne2) { continue; } var d = dn + dd; if (d < dmin) { dmin = d; } bit >>= 1; if (bit == 0) { rnd.UniformInt(); bit = 1 << 30; } if ((rndBits & bit) != 0) { ca[ci] = cj; ca[i] = cj; ci = cj; } else { ca[cj] = ci; ca[j] = ci; } } } if (dmin > deps) { dict[ha[0]] = i; // only sparsely populate hashtable for performance reasons } } Init(); }