private static void RandomPointsComparer(IPointDComparer comparer) { RectD bounds = new RectD(-100, -100, 200, 200); PointD[] points = GeoAlgorithms.RandomPoints(100, bounds, comparer, 2); for (int i = 0; i < points.Length; i++) { PointD p = points[i]; Assert.IsTrue(bounds.Contains(p)); if (i > 0) { Assert.AreEqual(+1, comparer.Compare(p, points[i - 1])); } if (i < points.Length - 1) { Assert.AreEqual(-1, comparer.Compare(p, points[i + 1])); } for (int j = 0; j < points.Length; j++) { if (i == j) { continue; } double distance = p.Subtract(points[j]).LengthSquared; Assert.GreaterOrEqual(distance, 4); } } }
/// <summary> /// Creates an <see cref="Array"/> of random <see cref="PointD"/> coordinates within the /// specified area, ensuring a specified pairwise minimum distance.</summary> /// <param name="count"> /// The number of <see cref="PointD"/> coordinates to create.</param> /// <param name="bounds"> /// The coordinates of the area containing all <see cref="PointD"/> coordinates.</param> /// <param name="comparer"> /// The <see cref="IPointDComparer"/> instance used to sort and search the collection of /// <see cref="PointD"/> coordinates.</param> /// <param name="distance"> /// The smallest Euclidean distance between any two <see cref="PointD"/> coordinates. /// </param> /// <returns> /// An <see cref="Array"/> containing <paramref name="count"/> randomly created <see /// cref="PointD"/> coordinates whose pairwise distance is equal to or greater than /// <paramref name="distance"/>.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="comparer"/> is a null reference.</exception> /// <exception cref="ArgumentOutOfRangeException"><para> /// <paramref name="count"/> is less than zero. /// </para><para>-or-</para><para> /// <paramref name="bounds"/> contains a <see cref="RectD.Width"/> or <see /// cref="RectD.Height"/> that is equal to or less than zero. /// </para><para>-or-</para><para> /// <paramref name="distance"/> is equal to or less than zero.</para></exception> /// <remarks><para> /// The returned <see cref="Array"/> is sorted using the specified <paramref /// name="comparer"/>, and never contains duplicate <see cref="PointD"/> coordinates. /// </para><note type="caution"> /// <b>RandomPoints</b> may enter an endless loop if <paramref name="distance"/> is too /// great relative to <paramref name="count"/> and <paramref name="bounds"/>. /// </note></remarks> public static PointD[] RandomPoints(int count, RectD bounds, IPointDComparer comparer, double distance) { if (count < 0) { ThrowHelper.ThrowArgumentOutOfRangeException( "count", count, Strings.ArgumentNegative); } if (bounds.Width <= 0 || bounds.Height <= 0) { ThrowHelper.ThrowArgumentOutOfRangeException( "bounds", bounds, Strings.ArgumentCoordinatesInvalid); } if (comparer == null) { ThrowHelper.ThrowArgumentNullException("comparer"); } if (distance <= 0) { ThrowHelper.ThrowArgumentOutOfRangeException( "distance", distance, Strings.ArgumentNotPositive); } distance *= distance; List <PointD> points = new List <PointD>(count); for (int i = 0; i < count; i++) { createPoint: PointD point = new PointD( bounds.X + MersenneTwister.Default.NextDouble() * bounds.Width, bounds.Y + MersenneTwister.Default.NextDouble() * bounds.Height); if (points.Count > 0) { int index = comparer.FindNearest(points, point); if (point.Subtract(points[index]).LengthSquared < distance) { goto createPoint; } } points.Add(point); points.Sort(comparer); } return(points.ToArray()); }