Notifications
Clear all

[Closed] The random point between three

it’s a challenge. Sounds easy. But can you find a point which is randomly distributed between three points?

let’s make it more interesting.

every point of these three has a probability weighted from 0 to 1.

so the function has to figure as:

fn getThreePointsRandom a b c seedvalue: probably:[1,1,1] =
(
        if seedvalue != unsupplied do seed seedvalue
        (<the_algorithm> a b c  probably)
)  

4 Replies

Without weights, what I’ll do is:
P = A + u * (C – A) + v * (B – A)
Where:

  • A , B ,C: the vertex of the face triangle
  • 0 <= u <= 1
  • 0 <= v <= 1

If u+v <= 1, then, P is inside the triangle ABC.
This distribution, just with two random values u and v between 0 and 1, with condition u+v<= 1 should be uniform.

But I can’t find how to take weights into account with this method.

Here’s a test of filling a triangle with 5000 points, with @Animatect distribution and mine.
Can’t find any difference (perhaps both are OK or both are wrong):


(
	delete objects
	gc()

	local A = [0,0,0]
	local B = [10,0,0]
	local C = [7,4,0]
	
	s = splineShape() 
	addNewSpline s 
	addKnot s 1 #corner #line A 
	addKnot s 1 #corner #line B 
	addKnot s 1 #corner #line C 
	close s 1
	updateShape s --update the shape
	s.wirecolor = yellow


	fn getRandBC =
	(
		local bc1 = random 0.0 1.0 
		local bc2 = random 0.0 1.0
		if bc1+bc2 > 1.0 do
		(
			bc1 = 1.0 - bc1
			bc2 = 1.0 - bc2
		)
		bc3 = 1.0 - bc1 - bc2
			
		[bc1,bc2,bc3]
	)

	fn pointCoordsBC barCoords =
	(
		P = barCoords[1]*A + barCoords[2]*B + barCoords[3]*C		
	)
	
	for k = 1 to 5000 do with undo off
	(
		barCoords = getRandBC()
		P = pointCoordsBC barCoords
		point pos:P centermarker:true cross:false wirecolor:blue
	)
	
	
	A = [0,5,0]
	B = [10,5,0]
	C = [7,9,0]
	
	s = splineShape() 
	addNewSpline s 
	addKnot s 1 #corner #line A 
	addKnot s 1 #corner #line B 
	addKnot s 1 #corner #line C 
	close s 1
	updateShape s --update the shape
	s.wirecolor = yellow


	fn getRandUV =
	(
		do
		(
			U = random 0.0 1.0
			V = random 0.0 1.0
		)
		while U+V > 1

		[U,V]
	)

	fn pointCoordsUV UVCoords =
	(
		P = A + UVCoords[1] * (C - A) + UVCoords[2] * (B - A) 		
	)
	
	for k = 1 to 5000 do with undo off
	(
		UVCoords = getRandUV()
		P = pointCoordsUV UVCoords
		point pos:P centermarker:true cross:false wirecolor:blue
	)
)
	

there is a theory (you can find some articles about) that the uniform random point in triangle is:

	fn baryRandom A B C =
	(
		r1 = random 0.0 1.0
		r2 = random 0.0 1.0
		(1 - (sqrt r1)) * a + (sqrt r1) * (1 - r2) * b + (sqrt r1) * r2 * c
	)

of course we can optimize it by calculation square root only once. i left it how it’s shown in the theory

so we have three bary coordinates:


_a = 1 - (sqrt r1)
_b = (sqrt r1) * (1 - r2) 
_c =  (sqrt r1) * r2 



using these coordinates and weights (0…1) in points A, B, and C we can calculate probability to have a pick in this position…

probability = _a * Aw + _b * Bw + _c * Cw
if (random 0.0 1.0) <= probability do <the pick>




This is really interesting, ok, I get the 1 in the algorithm is to keep the ratio kind of normalized, what would be interesting to know is why is the algorithm using square root, My guess is that it has something to do with the total area of the triangle times 2, but I can’t pinpoint exactly where it is coming from, any guess?