6

This subject has already been covered here, and my question is slightly different.

Preliminary warning: i'm quite a noob (and probably will continue to be unless i go back to school), but i do love some maths, the one i can't do with programming. Please excuse my lack of "academism". If the question is too informal, please let me know, i will ask my question elsewhere.

In an euclidean space I got a triangle ABC, quite special, i don't know how to name it :

  • A is (0, 0)
  • B is (width, 0)
  • C is (cx, cy)

So 3 numbers are enough to describe ABC.

I want to pick a random point inside ABC. How to do it ?

I tried the following: Get a random point in the parallelogram, then "squeeze" into ABC.

let randomPoint = (width, C) => {
    let r1 = Math.random()
    let y = C.y * r1
    let r2 = Math.random()
    let x = width * r2 * (1 - r1) + C.x * r1
    return new Point(x, y)
}

enter image description here Of course, there's to much points near C. So i believed i would be able to fix that by changing the distribution along y.

So i got better results:

let randomPoint = (width, C) => {
    let r1 = Math.random() * Math.random()
    let y = C.y * r1
    let r2 = Math.random()
    let x = width * r2 * (1 - r1) + C.x * r1
    return new Point(x, y)
}

enter image description here But this is very empiric, and obviously, this is not uniform.

Is there a way to change the computation of r1 the random number to have a distribution that will be uniform inside ABC ?

NB: i realize my self that it should be a simplier solution by mirroring point in the upper triangle (BCA') to the first triangle ABC. I will post the solution in an anwser. Still however any comment will be much appreciated since I feel myself like fumbling in the fog.

1 Answers1

3

Ok there is a simple solution which consist of...

i don't even know how to describe it properly...

to "remap the upper triangle to the lower over the diagonal".

So with a picture:

enter image description here

And by code (JS/pseudo-code):

let randomPoint1 = (width, C) => {

    let r1 = Math.random()
    let r2 = Math.random()

    // if over the diagonal, then flip r1 & r2
    if (r1 + r2 > 1) {
        r1 = (1 - r1)
        r2 = (1 - r2)
    }

    let x = width * r2 + C.x * r1
    let y = C.y * r1
    return new Point(x, y)
}

Once again, any mathematical words will be appreciated here. It's quite annoying to have problems and not being able to tell them because lacking vocabulary and mathematical rigor.

  • 1
    I have delete my answer, as I do not have the time at the moment to figure out what breaks the uniformness and how to overcome this break easily. At the moment your method with flipping looks better and is definitely a cool trick. (+1) – trancelocation Feb 07 '20 at 12:20
  • 2
    You could call this a rotation or inversion, and it's not "over the diagonal" but "about the midpoint" (of the diagonal and the parallelogram). The centre of symmetry here is not a line (the diagonal) but a point (its midpoint). You can imagine the transformation either as rotating the figure through $\pi$ (or, as you may prefer to call it, $180^\circ$) about the midpoint, or as inverting it through the midpoint (i.e. for each point draw a line through the midpoint and map it to its counterpart on the other side of the midpoint). Anyway, I think you've found the most elegant solution. – joriki Feb 07 '20 at 12:54
  • @joriki you're right it's a rotation around the midpoint, so i updated my illustration – Joseph Merdrignac Feb 09 '20 at 07:59