11

I need to generate n random points in general position in the plane, i.e. no three points can lie on a same line. Points should have coordinates that are integers and lie inside a fixed square m x m. What would be the best algorithm to solve such a problem?

Update: square is aligned with the axes.

Danylo Mysak
  • 1,395
  • 2
  • 13
  • 21
  • Is the square aligned with the axes? If so, the coordinates are actually just points on an m²-sized grid, I believe. – Fred Foo Aug 04 '11 at 19:14
  • Yes, it is so. The complication is that no three points should lie on a same line. – Danylo Mysak Aug 04 '11 at 19:19
  • 2
    I just wanted to point out that this is very much not random – LaC Aug 04 '11 at 19:36
  • What do you see as a line? Since you are using integers, there are few opportunities for actual collisions. – Brad Aug 04 '11 at 20:04
  • By line I mean a straight line. Well, I must guarantee that there are no collisions. And besides, if n is close to m or larger than m, collisions tend to happen much more often. – Danylo Mysak Aug 04 '11 at 20:10
  • 2
    @Danylo: "straight line" is still ambiguous :) Do you mean a Euclidean line, or a Manhattan/taxicab/L1 line? – Fred Foo Aug 04 '11 at 20:24

7 Answers7

4

Since they're integers within a square, treat them as points in a bitmap. When you add a point after the first, use Bresenham's algorithm to paint all pixels on each of the lines going through the new point and one of the old ones. When you need to add a new point, get a random location and check if it's clear; otherwise, try again. Since each pair of pixels gives a new line, and thus excludes up to m-2 other pixels, as the number of points grows you will have several random choices rejected before you find a good one. The advantage of the approach I'm suggesting is that you only pay the cost of going through all lines when you have a good choice, while rejecting a bad one is a very quick test.

(if you want to use a different definition of line, just replace Bresenham's with the appropriate algorithm)

LaC
  • 12,088
  • 5
  • 34
  • 38
2

Can't see any way around checking each point as you add it, either by (a) running through all of the possible lines it could be on, or (b) eliminating conflicting points as you go along to reduce the possible locations for the next point. Of the two, (b) seems like it could give you better performance.

John
  • 15,744
  • 9
  • 65
  • 107
  • I agree with your option (b), which in known in the constraint programming community as forward-checking, but the problem is that some pairs of points might eliminate more points than others, so this generate-and-test approach needs either backtracking or random restarts to be complete. – Fred Foo Aug 04 '11 at 20:22
  • I came up with an optimization of (a). You need to remember all currently existing lines, say, by their coefficents. When new point A is added you run through all of the existing points, for each point Bi build the ABi line and check (with binary search) whether it’s already in your set of lines. If so, point A needs to be regenerated. It’s close to n^2*log(n) for n << m. – Danylo Mysak Aug 04 '11 at 20:28
2

Similar to @LaC's answer. If memory is not a problem, you could do it like this:

Add all points on the plane to a list (L).
Shuffle the list.
For each point (P) in the list,
   For each point (Q) previously picked,
     Remove every point from L which are linear to P-Q.
   Add P to the picked list.

You could continue the outer loop until you have enough points, or run out of them.

Markus Jarderot
  • 79,575
  • 18
  • 131
  • 135
1

This might just work (though might be a little constrained on being random). Find the largest circle you can draw within the square (this seems very doable). Pick any n points on the circle, no three will ever be collinear :-).

This should be an easy enough task in code. Say the circle is centered at origin (so something of the form x^2 + y^2 = r^2). Assuming r is fixed and x randomly generated, you can solve to find y coordinates. This gives you two points on the circle for every x which are diametrically opposite. Hope this helps.

Edit: Oh, integer points, just noticed that. Thats a pity. I'm going to keep this solution up though - since I like the idea

kyun
  • 590
  • 3
  • 10
0

Here is a paper that can maybe solve your problem:

"POINT-SETS IN GENERAL POSITION WITH MANY SIMILAR COPIES OF A PATTERN"

by BERNARDO M. ABREGO AND SILVIA FERNANDEZ-MERCHANT

YesThatIsMyName
  • 1,291
  • 3
  • 19
  • 24
0

Both @LaC's and @MizardX's solution are very interesting, but you can combine them to get even better solution.

The problem with @LaC's solution is that you get random choices rejected. The more points you have already generated the harder it gets to generate new ones. If there is only one available position left you have slight chance of randomly choosing it (1/(n*m)).

In the @MizardX's solution you never get rejected choices, however if you directly implement the "Remove every point from L which are linear to P-Q." step you'll get worse complexity (O(n^5)).

Instead it would be better to use a bitmap to find which points from L are to be removed. The bitmap would contain a value indicating whether a point is free to use and what is its location on the L list or a value indicating that this point is already crossed out. This way you get worst-case complexity of O(n^4) which is probably optimal.

EDIT:

I've just found that question: Generate Non-Degenerate Point Set in 2D - C++ It's very similar to this one. It would be good to use solution from this answer Generate Non-Degenerate Point Set in 2D - C++. Modifying it a bit to use radix or bucket sort and adding all the n^2 possible points to the P set initially and shufflying it, one can also get worst-case complexity of O(n^4) with a much simpler code. Moreover, if space is a problem and @LaC's solution is not feasible due to space requirements, then this algorithm will just fit in without modifications and offer a decent complexity.

Community
  • 1
  • 1
ciamej
  • 6,263
  • 2
  • 25
  • 37
-1

um, you don't specify which plane.. but just generate 3 random numbers and assign to x,y, and z

if 'the plane' is arbitrary, then set z=o every time or something...

do a check on x and y to see if they are in your m boundary,

compare the third x,y pair to see if it is on the same line as the first two... if it is, then regenerate the random values.

Randy
  • 15,788
  • 1
  • 33
  • 51
  • 2
    every line in this answer is wrong in some small respect. take for example random number generation.. you don't generate arbitrary random numbers, you generate ones that are within the bounds. you don't compare the third one with the first two, you compare a new element with every possible pair.. – Karoly Horvath Aug 04 '11 at 19:19