public double NextDouble()
        {
            // Choose a uniform random offset along the rouletteWheel
            double offset = Rng.ContinuousUniformZeroToN(rouletteWheel[rouletteWheel.Count - 1]);
            // Determine which class-interval we are in
            int index; // Contains the index into the rouletteWheel of the containing class

            Algorithms.BinarySearch <double>(rouletteWheel, offset, out index);
            // Choose a uniformally distributed value from within the class
            double classLower = histogram.LowerBoundary(index);
            double classUpper = histogram.UpperBoundary(index);

            return(Rng.ContinuousUniform(classLower, classUpper));
        }
        //public static SinuousFaultGene CreateRandom(Grid2DDomain domain)
        //{
        //    double border   = Border(domain);
        //    double x0   = Rng.ContinuousUniform(domain.Min.X - border, domain.Max.X + border);
        //    double y0   = Rng.ContinuousUniform(domain.Min.Y - border, domain.Max.Y + border);
        //    double phi0 = Rng.ContinuousUniform(-tipTangentAngle, +tipTangentAngle);
        //    double x1   = Rng.ContinuousUniform(domain.Min.X - border, domain.Max.X + border);
        //    double y1   = Rng.ContinuousUniform(domain.Min.Y - border, domain.Max.Y + border);
        //    double phi1 = Rng.ContinuousUniform(-tipTangentAngle, +tipTangentAngle);
        //    double detachDepth = Rng.ContinuousUniform(MinDetachDepth(domain), MaxDetachDepth(domain));
        //    double maxHeave    = Rng.ContinuousUniform(MinMaxHeave(domain), MaxMaxHeave(domain), false);
        //    double dip         = Rng.ContinuousUniform(minFaultDip, maxFaultDip);
        //    return Create(domain, x0, y0, phi0, x1, y1, phi1, maxHeave, detachDepth, dip);
        //}

        public static SinuousFaultGene CreateRandom(Grid2DDomain domain)
        {
            // Select a point to be on the centre of a straight line
            // joining the fault tips
            double  border = Border(domain);
            Point2D centre = new Point2D(Rng.ContinuousUniform(domain.Min.X - border, domain.Max.X + border),
                                         Rng.ContinuousUniform(domain.Min.Y - border, domain.Max.Y + border));

            // Select a fault orientation - select a dip azimuth from the
            // distribution, and convert it into a fault strike.
            double dipAzimuth = domain.RandomHistogramDipAzimuth();
            // Fault strike should be 90° anti-clockwise of surface dip
            double faultStrike = dipAzimuth - Math.PI / 2.0;

            // Select a fault length from the domain length scale distribution
            double faultLength = Rng.ContinuousUniformZeroToN((domain.Max - domain.Min).Magnitude);

            Vector2D halfCentreLine = new Vector2D(Math.Cos(faultStrike) * faultLength / 2.0,
                                                   Math.Sin(faultStrike) * faultLength / 2.0);

            Point2D p0 = centre - halfCentreLine;
            Point2D p1 = centre + halfCentreLine;

            double phi0 = Rng.ContinuousUniform(-tipTangentAngle, +tipTangentAngle);
            double phi1 = Rng.ContinuousUniform(-tipTangentAngle, +tipTangentAngle);

            double detachDepth = Rng.ContinuousUniform(MinDetachDepth(domain), MaxDetachDepth(domain));

            double maxFaultHeave   = faultLength / minFaultDisplacementLengthRatio;
            double lowerFaultHeave = MinMaxHeave(domain);
            double upperFaultHeave = Math.Max(Math.Min(maxFaultHeave, detachDepth / 2.0) / 10.0, lowerFaultHeave);
            double maxHeave        = Rng.ContinuousUniform(lowerFaultHeave, upperFaultHeave, false);
            double dip             = Rng.ContinuousUniform(minFaultDip, maxFaultDip);

            return(Create(domain, p0.X, p0.Y, phi0, p1.X, p1.Y, phi1, maxHeave, detachDepth, dip));
        }