Skip to main content
added 1002 characters in body
Source Link
Andy Ross
  • 19.4k
  • 2
  • 61
  • 93

Edit 2:

Now for a more serious attempt at something efficient..

findPoints =
  Compile[{{n, _Integer}, {low, _Real}, {high, _Real}, {minD, _Real}},
   Block[{data = RandomReal[{low, high}, {1, 2}], k = 1, rv, temp},
    While[k < n,
     rv = RandomReal[{low, high}, 2];
     temp = Transpose[Transpose[data] - rv];
     If[Min[Sqrt[(#.#)] & /@ temp] > minD,
      data = Join[data, {rv}];
      k++;
      ];
     ];
    data
    ]
   ];

And to test it for benchmarking...

npts = 350;
minD = 3;
low = 0;
high = 100;

AbsoluteTiming[pts = findPoints[npts, low, high, minD];]

==> {0.0312004, Null}

Check that the min distance is less than the threshold.

Min[
  MapThread[
   EuclideanDistance, {pts, Nearest[pts][#, 2][[-1]] & /@ pts}]] > minD

==> True

Check that I generated the correct number of points..

Length[pts] == npts

==> True

Edit 2:

Now for a more serious attempt at something efficient..

findPoints =
  Compile[{{n, _Integer}, {low, _Real}, {high, _Real}, {minD, _Real}},
   Block[{data = RandomReal[{low, high}, {1, 2}], k = 1, rv, temp},
    While[k < n,
     rv = RandomReal[{low, high}, 2];
     temp = Transpose[Transpose[data] - rv];
     If[Min[Sqrt[(#.#)] & /@ temp] > minD,
      data = Join[data, {rv}];
      k++;
      ];
     ];
    data
    ]
   ];

And to test it for benchmarking...

npts = 350;
minD = 3;
low = 0;
high = 100;

AbsoluteTiming[pts = findPoints[npts, low, high, minD];]

==> {0.0312004, Null}

Check that the min distance is less than the threshold.

Min[
  MapThread[
   EuclideanDistance, {pts, Nearest[pts][#, 2][[-1]] & /@ pts}]] > minD

==> True

Check that I generated the correct number of points..

Length[pts] == npts

==> True
added 135 characters in body
Source Link
Andy Ross
  • 19.4k
  • 2
  • 61
  • 93

This is not an efficient answer but it is fun to play with so I thought I'd post it. For efficiency the use of Nearest might provide a good starting point.

g[n_, {low_, high_}, minDist_, step_: 1] := 
 Block[{data = RandomReal[{low, high}, {n, 2}], temp, happy, sdata, 
   hdata},
  
  While[True,
   temp = ((Nearest[data][#, 2][[-1]] & /@ data));
   happy = 
    Boole@Thread[MapThread[EuclideanDistance, {temp, data}] > minDist];
   hdata = Pick[data, happy, 1];
   sdata = Pick[data, happy, 0];
   If[sdata === {}, Break[]];
   sdata += RandomReal[{-step, step}, {Length[sdata], 2}];
   data = Join[sdata, hdata];
   ];
  data
  ]

The idea is to do an initial sampling and then allow the points that are too close to "walk" somewhere else. The function takes a desired number of points n, a low and high value for the data range, the minimum acceptable distance between points minDist and a step argument which allows points to "walk" up to a certain distance in the x and y directions.

Its especially fun to watch dynamically.

g[150, {0, 30}, 1.5, 1]

enter image description hereEdit: Per suggestion of Yves Klett the points are colored by relative happiness (green being more happy, red being less happy).

enter image description here

This is not an efficient answer but it is fun to play with so I thought I'd post it. For efficiency the use of Nearest might provide a good starting point.

g[n_, {low_, high_}, minDist_, step_: 1] := 
 Block[{data = RandomReal[{low, high}, {n, 2}], temp, happy, sdata, 
   hdata},
  
  While[True,
   temp = ((Nearest[data][#, 2][[-1]] & /@ data));
   happy = 
    Boole@Thread[MapThread[EuclideanDistance, {temp, data}] > minDist];
   hdata = Pick[data, happy, 1];
   sdata = Pick[data, happy, 0];
   If[sdata === {}, Break[]];
   sdata += RandomReal[{-step, step}, {Length[sdata], 2}];
   data = Join[sdata, hdata];
   ];
  data
  ]

The idea is to do an initial sampling and then allow the points that are too close to "walk" somewhere else. The function takes a desired number of points n, a low and high value for the data range, the minimum acceptable distance between points minDist and a step argument which allows points to "walk" up to a certain distance in the x and y directions.

Its especially fun to watch dynamically.

g[150, {0, 30}, 1.5, 1]

enter image description here

This is not an efficient answer but it is fun to play with so I thought I'd post it. For efficiency the use of Nearest might provide a good starting point.

g[n_, {low_, high_}, minDist_, step_: 1] := 
 Block[{data = RandomReal[{low, high}, {n, 2}], temp, happy, sdata, 
   hdata},
  
  While[True,
   temp = ((Nearest[data][#, 2][[-1]] & /@ data));
   happy = 
    Boole@Thread[MapThread[EuclideanDistance, {temp, data}] > minDist];
   hdata = Pick[data, happy, 1];
   sdata = Pick[data, happy, 0];
   If[sdata === {}, Break[]];
   sdata += RandomReal[{-step, step}, {Length[sdata], 2}];
   data = Join[sdata, hdata];
   ];
  data
  ]

The idea is to do an initial sampling and then allow the points that are too close to "walk" somewhere else. The function takes a desired number of points n, a low and high value for the data range, the minimum acceptable distance between points minDist and a step argument which allows points to "walk" up to a certain distance in the x and y directions.

Its especially fun to watch dynamically.

g[150, {0, 30}, 1.5, 1]

Edit: Per suggestion of Yves Klett the points are colored by relative happiness (green being more happy, red being less happy).

enter image description here

Source Link
Andy Ross
  • 19.4k
  • 2
  • 61
  • 93

This is not an efficient answer but it is fun to play with so I thought I'd post it. For efficiency the use of Nearest might provide a good starting point.

g[n_, {low_, high_}, minDist_, step_: 1] := 
 Block[{data = RandomReal[{low, high}, {n, 2}], temp, happy, sdata, 
   hdata},
  
  While[True,
   temp = ((Nearest[data][#, 2][[-1]] & /@ data));
   happy = 
    Boole@Thread[MapThread[EuclideanDistance, {temp, data}] > minDist];
   hdata = Pick[data, happy, 1];
   sdata = Pick[data, happy, 0];
   If[sdata === {}, Break[]];
   sdata += RandomReal[{-step, step}, {Length[sdata], 2}];
   data = Join[sdata, hdata];
   ];
  data
  ]

The idea is to do an initial sampling and then allow the points that are too close to "walk" somewhere else. The function takes a desired number of points n, a low and high value for the data range, the minimum acceptable distance between points minDist and a step argument which allows points to "walk" up to a certain distance in the x and y directions.

Its especially fun to watch dynamically.

g[150, {0, 30}, 1.5, 1]

enter image description here