/// <summary>
        /// Compose a random point whose values fall between Minimum (inclusive) and Maximum (exclusive) but
        /// which is no closer to all previous points than MinimumDistance.
        ///
        /// NOTE: If too many unsuccessful attempts are made to find such a point, null will be returned instead.
        /// </summary>
        /// <param name="point">Point whose coordinate values will be changed.
        /// The values will be changed in place.
        /// This array must have at least as many elements as Dimensions.
        /// </param>
        /// <returns>The same point with changes made, or null, if no point could be found.</returns>
        public override int[] Generate(int[] p)
        {
            UnsignedPoint pt;
            var           intPoint = FindSeparatedPoint(out pt);

            if (intPoint != null)
            {
                PreviousPoints.Add(pt);
                Array.Copy(intPoint, p, Dimensions);
                return(p);
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// Find a point far enough away from the previous points,
        /// but do not record it yet as a Previous Point.
        /// </summary>
        /// <param name="uPoint">UnsignedPoint made from the returned array, or null.</param>
        /// <returns>A point well-separated from all previous points, or null if none could be found.
        /// </returns>
        public int[] FindSeparatedPoint(out UnsignedPoint uPoint)
        {
            var minDistSquared = (long)Math.Ceiling(MinimumDistance * MinimumDistance);
            var tries          = 0;
            var point          = new int[Dimensions];

            while (tries < 100)
            {
                for (var iDim = 0; iDim < AffectedDimensions.Count; iDim++)
                {
                    point[iDim] = Rng.Next(Minimum, Maximum);
                }
                var pt = new UnsignedPoint(point); // Copies the array.
                if (!PreviousPoints.Any(p => p.Measure(pt) < minDistSquared))
                {
                    uPoint = pt;
                    return(point);
                }
                tries++;
            }
            uPoint = null;
            return(null);
        }
        /// <summary>
        /// Generate a chain of close points, each seperated by the given segmentLength.
        /// No points from this chain will be close to any points from previous chains.
        /// </summary>
        /// <param name="chainLength"></param>
        /// <param name="segmentLength"></param>
        /// <returns>A list of chainLength points (or fewer, if we can't find any more).</returns>
        public List <int[]> GenerateChain(int chainLength, int segmentLength)
        {
            var           segSquaredLength     = (long)segmentLength * segmentLength;
            var           chain                = new List <int[]>();
            var           currentUnsignedChain = new List <UnsignedPoint>();
            UnsignedPoint uPoint               = null;
            var           currentPoint         = FindSeparatedPoint(out uPoint);

            if (currentPoint == null)
            {
                return(chain);
            }
            currentUnsignedChain.Add(uPoint);
            chain.Add(currentPoint);
            var failures = 0;

            while (chain.Count() < chainLength && failures < 20)
            {
                var nextPoint = RandomStep(currentPoint, segmentLength);
                uPoint = new UnsignedPoint(nextPoint);
                if (IsSeparatedPoint(uPoint))
                {
                    chain.Add(nextPoint);
                    currentUnsignedChain.Add(uPoint);
                    currentPoint = nextPoint;
                }
                else
                {
                    failures++;
                }
            }
            PreviousPoints.AddRange(currentUnsignedChain);
            var startToFinishDistance = currentUnsignedChain.First().Distance(currentUnsignedChain.Last());

            return(chain);
        }
        public bool IsSeparatedPoint(UnsignedPoint pt)
        {
            var minDistSquared = (long)Math.Ceiling(MinimumDistance * MinimumDistance);

            return(!PreviousPoints.Any(p => p.Measure(pt) < minDistSquared));
        }