> I found this neat technique, to find random points in a circle where a random radius r and angle theta are chosen and the x,y points are obtained as x = centerX + r * cos(theta) and y = centerY + r * sin(theta)
This misses the crucial point of the technique described in the linked Stackoverflow answer: that r cannot be a uniformly distributed random value if you want a uniform distribution of points in a circle. Rather you need
r = R * sqrt(random())
where R is the radius of the circle and random() gives a uniform distribution of random numbers between 0 and 1.
Not really, about π/4 = 79% of the times you will have a single iteration. The expected number of iterations is the geometric series with this ratio, which is smaller than 2.
The flowlines of any vector field cannot intersect, because that would mean the flowline has two tangent vectors at that point. For smooth vector fields, they cannot merge either, an intuition for that is perhaps that you could theoretically run the flow "in reverse", which would turn a merger into a split, and that's not possible.
The Perlin noise is generating a scalar field in this case (which gives the direction of the movement vector at each point). Here's a very similar bit of code that can be tweaked easily: https://openprocessing.org/sketch/494102/
Setting the particle speed to more than about 0.5 (on line 46) results in "aberrations". The dynamics are quite interesting and I'm not sure exactly what's going on, but I think wetmore's answer is correct—when the steps are small enough, everything remains as smooth as the underlying scalar field produced by Perlin noise.
This misses the crucial point of the technique described in the linked Stackoverflow answer: that r cannot be a uniformly distributed random value if you want a uniform distribution of points in a circle. Rather you need
where R is the radius of the circle and random() gives a uniform distribution of random numbers between 0 and 1.