Related
I'm looking for an algorithm that can generate points within a cone with a flat bottom (a disk).
I have the normalized axis along which the cone is being created (for our purposes let's just say it is the y-axis so (0, 1, 0) and the angle of the cone (let's say it is 45 degrees).
The only resources I could find online generate vectors within a cone, but they are based on sampling a sphere, so at the bottom you get a kind of "snow-cone" effect instead of a disk at the bottom.
That is done with the following pseudocode:
// Sample phi uniformly on [0, 2PI]
float phi = rand(0, 1) * 2 * PI
// Sample u uniformly from [cos(angle), 1]
float u = rand(0, 1) * (1 - cos(angle * PI/180)) + cos(angle * PI/180)
vec3 = vec3(sqrt(1 - u^2) * cos(phi), u, sqrt(1 - u^2) * sin(phi)))
The below picture is what I am going for. Having the ability to generate samples either on the surface or inside would be nice as well:
I could explain my solution in detail using integrals and probability distributions, but the lack of MathJax on this site makes that difficult. I'll keep my explanation at a simple level, but it should be clear. I'll also make the solution a little more general than you ask: we want a random point inside a right circular cone of height a and radius of base b, and we want the point with uniform sampling over the volume of that cone. This method directly chooses a random point in the cone without any rejection testing.
First let's consider the small cone of height h inside that larger cone, both cones with the same apex and parallel bases. The two cones are of course similar figures, and the square-cube law says that the volume of the smaller cone varies as the cube of its height. That height varies from 0 to a and we want its cube to be uniform over that range. Therefore we choose h to vary with the cube root of a uniform random variable, and we get (in Python 3 code),
h = a * (random()) ** (1/3)
We next consider the circular region that is the base of that smaller cone of height h. The radius of that base is (b / a) * h, by similar triangles. Now think of a smaller circular region of radius r inside that larger circular region, both circles in the same plane and with the same center. The area of the smaller circle varies with the square of its radius, so to get a uniform area over its range we take the square root of a uniform random variable. We get
r = (b / a) * h * sqrt(random())
We now want the angle t (for theta) of a point on the circumference of that smaller circle of radius r. The angle in radians obviously does not depend on the other factors, so we just use a uniform random variable to get
t = 2 * pi * random()
We now use those three random variables h, r, and t to choose our point inside the starting cone. If the apex of the cone is at the origin and the axis of the cone is along the positive y-axis, so that the center of the base is (0, a, 0) and a point on the circumference of the base is (b, a, 0), you can choose
x = r * cos(t)
y = h
z = r * sin(t)
When you asked about generating samples "on the surface" you did not clarify if you mean just the side (or is it "sides"?) of the cone, just the base, or the entire surface. Your second graphic appears to mean just the side, but I'll give code for all three.
The side only
Again we use a smaller cone of height h inside the larger cone. Its surface area varies as the square of its height, so we take the square root of a uniform random variable. The circle in its base is fixed, if our point is to be on the surface, and again the angle is just uniform. So we get
h = a * sqrt(random())
r = (b / a) * h
t = 2 * pi * random()
Use the same code for x, y, and z I used above for the interior of the cone to get the final random point on the side surface of the cone.
The base only
This is much like choosing a point in the interior, except the height is predetermined to equal the height of the entire cone. We get the following, somewhat simplified code:
h = a
r = b * sqrt(random())
t = 2 * pi * random()
Again, use the previous code for the final x, y, and z.
The entire surface
Here we can first decide, at random, whether to place our point on the base or on the surface, then place the point in one of the two ways above. The area of the base of a cone of height a and base radius b is pi * b * b while the surface area of the cone's side is pi * b * sqrt(a*a + b*b). We use the ratio of the base to the total of those areas to choose which subsurface to use for our point:
if random() < b / (b + sqrt(a*a + b*b)):
return point_on_base(a, b)
else:
return point_on_side(a, b)
Use my codes above for the side and base to complete that code.
Here are simple matplotlib 3D scatter plots of 10,000 random points, first inside the cone then on its side surface. Note that I made the apex angle 45°, as your text states but unlike your pictures. Viewing these from other angles seems to confirm that they are uniform in volume or area.
I have been trying to understand Jacobian Determinant.
I hope someone is able to give me a pointer.
Most material that I found on Internet didn't provide
derivation of Jacobian Determinant.
One such web site is:
http://tutorial.math.lamar.edu
(Which I find quite good, otherwise.)
I spent a lot of time trying to deepen my understanding of
Jacobian Determinant.
I played with Transformations that define uv-axes and
how integration of a function over a Region/area would work
with the Transformations.
For example, when I started with simple Transformations of:
u = ( x - y )/√2
v = ( x + y )/2√2
which is uv-axes rotated -45° from Cartesian xy-axes,
and with v-axis at 2 times the scale,
that is, v = 1 maps to 2 units length in xy-coords.
So, I say that uscale = 1, vscale = 2,
for the above transformations.
With this uv-axes, I can simplify a 10x20 rectangle Region
which is rotated at 45° from x-axis,
such that the longer dimension points at 45° from x-axis.
With such examples, I begin to develop intuition
how Jacobian Determinant works.
I understand Jacobian Determinant to be a Scaling Factor
to convert area measurement in uv-axes to xy-dimensions.
Area measurement in uv-axes is given simply by formula
Δu x Δv, where Δu = 10, Δv = 10, because vscale = 2).
Jacobian Determinant Scaling Factor = uscale x vscale
(quite intuitively).
Area in xy-dimensions = Δu x Δv x (uscale x vscale)
= 10 x 10 x 1 x 2 = 200.
Integration of volume over such a simpler uv Square,
could be easier than over the same xy Region,
appearing at an angle.
With the above initial understanding,
I am trying to work out how Jacobian Determinant is derived.
Deriving from the above Transformations formula:
dx/du = √2 / 2
dx/dv = √2
dy/du = -√2 / 2
dy/dv = √2
I can also derive from Geometry that:
dx/du = uscale cos Θ
dy/du = uscale sin Θ
dx/dv = vscale cos (90° - Θ)
dy/dv = vscale sin (90° - Θ)
I could get:
areaInXY / areaInUV = uscale x vscale
which matches my understanding.
However, Jacobian Determinant formula is:
∂(x, y) / ∂(u, v) = ∂x/∂u ∂y/∂v - ∂x/∂v ∂y/∂u
= uscale * vscale * cos 2Θ
This leaves me quite puzzled why I have the extra cos 2Θ factor
which isn't making intuitive sense -- why would the
area Scaling Factor depends on how the rectangle is rotated
and thus how uv-axes are rotated?!
Anybody can see where my reasoning went wrong above?
Let me try to explain what basically the Jacobian determinant does. This is true in general for smooth functions mapping from R^n to R^n, but for the sake of simplicity, assume we are working on R^2. Let F(x,y) a smooth R^2 to R^2 function. Then we can say that F(x,y) sends the x coordinate to f1(x,y) and the y coordiate to f2(x,y) at point (x,y). Then think about an infinitesimal rectangular area, defined by the points (x,y),(x+dx,y),(x,y+dy) and (x+dx,y+dy). Now, the area of this infinitesimal rectangle is dxdy. What happens to this rectangle when it goes through the F(x,y) transformation? We apply F(x,y) to each of the four coordinates and obtain the following points:
A:(x,y)->(f1(x,y),f2(x,y))
B:(x+dx,y) -> (f1(x+dx,y),f2(x+dx,y)) (approx.)= (f1(x,y) + (∂f1/∂x)dx,f2(x,y) + (∂f2/∂x)dx)
C:(x,y+dy) -> (f1(x,y+dy),f2(x,y+dy)) (approx.)= (f1(x,y) + (∂f1/∂y)dy,f2(x,y) + (∂f2/∂y)dy)
D:(x+dx,y+dy) -> (f1(x+dx,y+dy),f2(x+dx,y+dy)) (approx.)=(f1(x,y) + (∂f1/∂x)dx + (∂f1/∂y)dy,f2(x,y) + (∂f2/∂x)dx + (∂f2/∂y)dy)
The equalities are approximately equal and exactly hold in the limit where dx and dy goes to 0, they are the best linear approximation to the function F at new points. (We obtain these from the first order parts of the Taylor approximation of the functions f1 and f2).
If we look to the new (approximated) area under the transformation F(x,y), we see the new distance vectors between the transformed points a:
B-A:((∂f1/∂x)dx,(∂f2/∂x)dx)
C-A:((∂f1/∂y)dy,(∂f2/∂y)dy)
D-C:((∂f1/∂x)dx,(∂f2/∂x)dx)
D-B:((∂f1/∂y)dy,(∂f2/∂y)dy)
As you can see, the newly transformed infinitesimal area is a parallelogram. Let:
u=((∂f1/∂x)dx,(∂f2/∂x)dx)
v=((∂f1/∂y)dy,(∂f2/∂y)dy)
These vectors constitute the edges of our parallelogram. It can be shown with the help of the cross product between u and v, that the area of the parallelogram is:
area^2 = (u1v2 - u2v1)^2 = ((∂f1/∂x)(∂f2/∂y)dxdy - (∂f2/∂x)(∂f1/∂y)dxdy)^2
area^2 = ((∂f1/∂x)(∂f2/∂y) - (∂f2/∂x)(∂f1/∂y))^2 (dxdy)^2
area = |(∂f1/∂x)(∂f2/∂y) - (∂f2/∂x)(∂f1/∂y)|dxdy (dx and dy are positive)
area = |det([∂f1/∂x, ∂f1/∂y],[∂f2/∂x, ∂f2/∂y])|dxdy
So, the matrix we are going to take the determinant of is simply the Jacobian matrix. Like I said in the beginning, this derivation can be extended to arbitrary dimensions of n,given the coordinate transformation function F is smooth and the Jacobian matrix is hence invertible, with non-zero determinant.
A good visual explanation of this is given at: http://mathinsight.org/double_integral_change_variables_introduction
If I have X amount of things (lets just randomly say 300)
Is there an algorithm that will arrange these things somewhat evenly around a central point? Like a 100 sided dice or a 3d mesh of a sphere?
Id rather have the things somewhat evenly spaced like this..
Rather than this polar way..
ps. For those interested, wondering why do I want to do this?
Well I'm doing these for fun, and after completing #7 I decided I'd like to represent the array of wires in 3d in Unity and watch them operate in a slowed down manner.
Here is a simple transformation that maps a uniform sample in the rectangle [0, 2 pi] x [-1, 1] onto a uniform sample on the sphere of radius r:
T(phi, z) = (r cos(phi) sqrt(1 - z^2), r sin(phi) sqrt(1 - zˆ2), r z)
The reason why this transformation produces uniform samples on the sphere is that the area of any region T(U) obtained by transforming the region U from the rectangle does not depend on U but on the area of U.
To prove this mathematically it is enough to verify that the norm of the vectorial product
| ∂T/∂phi x ∂T/∂z |
is constant (the area on the sphere is the integral of this vectorial product w.r.t. phi and z).
Summarizing
To produce a random sample uniformly distributed in the Sphere of radius r do the following:
Produce a random sample (phi_1, ..., phi_n) uniformly distributed in [0, 2 pi].
Produce a random sample (z_1, ..., z_n) uniformly distributed in [-1, 1].
For every pair (phi_j, z_k) calculate T(phi_j, z_k) using the formula above.
Here's a three-step approach. 1a) Make more points than you need. 1b) Remove some. 2) Adjust the rest.
1a) To make more points that you need, take any quasiregular polyhedron with sides that tessellate (triangles, squares, diamonds). Tesselate the spherical faces by subdivision, generating more vertices. For example, if you use the regular icosahedron you get geodesic domes. (Subdivide by 2, you get the dual to the C60 buckyball.) Working out exact formulas isn't hard. The number of new vertices per face is quadratic in the subdivision.
1b) Randomly remove enough points to get you down to your target number.
2) Use a force-directed layout algorithm to redistribute the vertices over the sphere. The underlying force graph is just that provided by the nearest neighbors in your underlying tesselation.
There are other ways to do step 1), such as just generating random points in any distribution. There is an advantage of starting with a quasiregular figure, though. Force-directed algorithms have a reputation for poor convergence in some cases. By starting with something that's already mostly optimal, you'll bypass most all of any convergence problems you might have.
One elegant solution I came across recently is a spherical fibonacci lattice (http://extremelearning.com.au/how-to-evenly-distribute-points-on-a-sphere-more-effectively-than-the-canonical-fibonacci-lattice/)
The nice thing about it is that you can specify the exact number of points you want
// C# Code example
Vector3[] SphericalFibonacciLattice(int n) {
Vector3[] res = new Vector3[n];
float goldenRatio = (1.0f + MathF.Sqrt(5.0f)) * 0.5f;
for(int i = 0; i < n; i++)
{
float theta = 2.0f * MathF.PI * i / goldenRatio;
float phi = MathF.Acos(1.0f - 2.0f * (i + 0.5f) / n);
Vector3 p = new Vector3(MathF.Cos(theta) * MathF.Sin(phi),
MathF.Sin(theta) * MathF.Sin(phi),
MathF.Cos(phi));
res[i] = p;
}
return res;
}
The linked article extends on this to create an even more uniform distribution, but even this basic version creates very nice results.
I need to generate a uniformly random point within a circle of radius R.
I realize that by just picking a uniformly random angle in the interval [0 ... 2π), and uniformly random radius in the interval (0 ... R) I would end up with more points towards the center, since for two given radii, the points in the smaller radius will be closer to each other than for the points in the larger radius.
I found a blog entry on this over here but I don't understand his reasoning. I suppose it is correct, but I would really like to understand from where he gets (2/R2)×r and how he derives the final solution.
Update: 7 years after posting this question I still hadn't received a satisfactory answer on the actual question regarding the math behind the square root algorithm. So I spent a day writing an answer myself. Link to my answer.
How to generate a random point within a circle of radius R:
r = R * sqrt(random())
theta = random() * 2 * PI
(Assuming random() gives a value between 0 and 1 uniformly)
If you want to convert this to Cartesian coordinates, you can do
x = centerX + r * cos(theta)
y = centerY + r * sin(theta)
Why sqrt(random())?
Let's look at the math that leads up to sqrt(random()). Assume for simplicity that we're working with the unit circle, i.e. R = 1.
The average distance between points should be the same regardless of how far from the center we look. This means for example, that looking on the perimeter of a circle with circumference 2 we should find twice as many points as the number of points on the perimeter of a circle with circumference 1.
Since the circumference of a circle (2πr) grows linearly with r, it follows that the number of random points should grow linearly with r. In other words, the desired probability density function (PDF) grows linearly. Since a PDF should have an area equal to 1 and the maximum radius is 1, we have
So we know how the desired density of our random values should look like.
Now: How do we generate such a random value when all we have is a uniform random value between 0 and 1?
We use a trick called inverse transform sampling
From the PDF, create the cumulative distribution function (CDF)
Mirror this along y = x
Apply the resulting function to a uniform value between 0 and 1.
Sounds complicated? Let me insert a blockquote with a little side track that conveys the intuition:
Suppose we want to generate a random point with the following distribution:
That is
1/5 of the points uniformly between 1 and 2, and
4/5 of the points uniformly between 2 and 3.
The CDF is, as the name suggests, the cumulative version of the PDF. Intuitively: While PDF(x) describes the number of random values at x, CDF(x) describes the number of random values less than x.
In this case the CDF would look like:
To see how this is useful, imagine that we shoot bullets from left to right at uniformly distributed heights. As the bullets hit the line, they drop down to the ground:
See how the density of the bullets on the ground correspond to our desired distribution! We're almost there!
The problem is that for this function, the y axis is the output and the x axis is the input. We can only "shoot bullets from the ground straight up"! We need the inverse function!
This is why we mirror the whole thing; x becomes y and y becomes x:
We call this CDF-1. To get values according to the desired distribution, we use CDF-1(random()).
…so, back to generating random radius values where our PDF equals 2x.
Step 1: Create the CDF:
Since we're working with reals, the CDF is expressed as the integral of the PDF.
CDF(x) = ∫ 2x = x2
Step 2: Mirror the CDF along y = x:
Mathematically this boils down to swapping x and y and solving for y:
CDF: y = x2
Swap: x = y2
Solve: y = √x
CDF-1: y = √x
Step 3: Apply the resulting function to a uniform value between 0 and 1
CDF-1(random()) = √random()
Which is what we set out to derive :-)
Let's approach this like Archimedes would have.
How can we generate a point uniformly in a triangle ABC, where |AB|=|BC|? Let's make this easier by extending to a parallelogram ABCD. It's easy to generate points uniformly in ABCD. We uniformly pick a random point X on AB and Y on BC and choose Z such that XBYZ is a parallelogram. To get a uniformly chosen point in the original triangle we just fold any points that appear in ADC back down to ABC along AC.
Now consider a circle. In the limit we can think of it as infinitely many isoceles triangles ABC with B at the origin and A and C on the circumference vanishingly close to each other. We can pick one of these triangles simply by picking an angle theta. So we now need to generate a distance from the center by picking a point in the sliver ABC. Again, extend to ABCD, where D is now twice the radius from the circle center.
Picking a random point in ABCD is easy using the above method. Pick a random point on AB. Uniformly pick a random point on BC. Ie. pick a pair of random numbers x and y uniformly on [0,R] giving distances from the center. Our triangle is a thin sliver so AB and BC are essentially parallel. So the point Z is simply a distance x+y from the origin. If x+y>R we fold back down.
Here's the complete algorithm for R=1. I hope you agree it's pretty simple. It uses trig, but you can give a guarantee on how long it'll take, and how many random() calls it needs, unlike rejection sampling.
t = 2*pi*random()
u = random()+random()
r = if u>1 then 2-u else u
[r*cos(t), r*sin(t)]
Here it is in Mathematica.
f[] := Block[{u, t, r},
u = Random[] + Random[];
t = Random[] 2 Pi;
r = If[u > 1, 2 - u, u];
{r Cos[t], r Sin[t]}
]
ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]
Here is a fast and simple solution.
Pick two random numbers in the range (0, 1), namely a and b. If b < a, swap them. Your point is (b*R*cos(2*pi*a/b), b*R*sin(2*pi*a/b)).
You can think about this solution as follows. If you took the circle, cut it, then straightened it out, you'd get a right-angled triangle. Scale that triangle down, and you'd have a triangle from (0, 0) to (1, 0) to (1, 1) and back again to (0, 0). All of these transformations change the density uniformly. What you've done is uniformly picked a random point in the triangle and reversed the process to get a point in the circle.
Note the point density in proportional to inverse square of the radius, hence instead of picking r from [0, r_max], pick from [0, r_max^2], then compute your coordinates as:
x = sqrt(r) * cos(angle)
y = sqrt(r) * sin(angle)
This will give you uniform point distribution on a disk.
http://mathworld.wolfram.com/DiskPointPicking.html
Think about it this way. If you have a rectangle where one axis is radius and one is angle, and you take the points inside this rectangle that are near radius 0. These will all fall very close to the origin (that is close together on the circle.) However, the points near radius R, these will all fall near the edge of the circle (that is, far apart from each other.)
This might give you some idea of why you are getting this behavior.
The factor that's derived on that link tells you how much corresponding area in the rectangle needs to be adjusted to not depend on the radius once it's mapped to the circle.
Edit: So what he writes in the link you share is, "That’s easy enough to do by calculating the inverse of the cumulative distribution, and we get for r:".
The basic premise is here that you can create a variable with a desired distribution from a uniform by mapping the uniform by the inverse function of the cumulative distribution function of the desired probability density function. Why? Just take it for granted for now, but this is a fact.
Here's my somehwat intuitive explanation of the math. The density function f(r) with respect to r has to be proportional to r itself. Understanding this fact is part of any basic calculus books. See sections on polar area elements. Some other posters have mentioned this.
So we'll call it f(r) = C*r;
This turns out to be most of the work. Now, since f(r) should be a probability density, you can easily see that by integrating f(r) over the interval (0,R) you get that C = 2/R^2 (this is an exercise for the reader.)
Thus, f(r) = 2*r/R^2
OK, so that's how you get the formula in the link.
Then, the final part is going from the uniform random variable u in (0,1) you must map by the inverse function of the cumulative distribution function from this desired density f(r). To understand why this is the case you need to find an advanced probability text like Papoulis probably (or derive it yourself.)
Integrating f(r) you get F(r) = r^2/R^2
To find the inverse function of this you set u = r^2/R^2 and then solve for r, which gives you r = R * sqrt(u)
This totally makes sense intuitively too, u = 0 should map to r = 0. Also, u = 1 shoudl map to r = R. Also, it goes by the square root function, which makes sense and matches the link.
Let ρ (radius) and φ (azimuth) be two random variables corresponding to polar coordinates of an arbitrary point inside the circle. If the points are uniformly distributed then what is the disribution function of ρ and φ?
For any r: 0 < r < R the probability of radius coordinate ρ to be less then r is
P[ρ < r] = P[point is within a circle of radius r] = S1 / S0 =(r/R)2
Where S1 and S0 are the areas of circle of radius r and R respectively.
So the CDF can be given as:
0 if r<=0
CDF = (r/R)**2 if 0 < r <= R
1 if r > R
And PDF:
PDF = d/dr(CDF) = 2 * (r/R**2) (0 < r <= R).
Note that for R=1 random variable sqrt(X) where X is uniform on [0, 1) has this exact CDF (because P[sqrt(X) < y] = P[x < y**2] = y**2 for 0 < y <= 1).
The distribution of φ is obviously uniform from 0 to 2*π. Now you can create random polar coordinates and convert them to Cartesian using trigonometric equations:
x = ρ * cos(φ)
y = ρ * sin(φ)
Can't resist to post python code for R=1.
from matplotlib import pyplot as plt
import numpy as np
rho = np.sqrt(np.random.uniform(0, 1, 5000))
phi = np.random.uniform(0, 2*np.pi, 5000)
x = rho * np.cos(phi)
y = rho * np.sin(phi)
plt.scatter(x, y, s = 4)
You will get
The reason why the naive solution doesn't work is that it gives a higher probability density to the points closer to the circle center. In other words the circle that has radius r/2 has probability r/2 of getting a point selected in it, but it has area (number of points) pi*r^2/4.
Therefore we want a radius probability density to have the following property:
The probability of choosing a radius smaller or equal to a given r has to be proportional to the area of the circle with radius r. (because we want to have a uniform distribution on the points and larger areas mean more points)
In other words we want the probability of choosing a radius between [0,r] to be equal to its share of the overall area of the circle. The total circle area is pi*R^2, and the area of the circle with radius r is pi*r^2. Thus we would like the probability of choosing a radius between [0,r] to be (pi*r^2)/(pi*R^2) = r^2/R^2.
Now comes the math:
The probability of choosing a radius between [0,r] is the integral of p(r) dr from 0 to r (that's just because we add all the probabilities of the smaller radii). Thus we want integral(p(r)dr) = r^2/R^2. We can clearly see that R^2 is a constant, so all we need to do is figure out which p(r), when integrated would give us something like r^2. The answer is clearly r * constant. integral(r * constant dr) = r^2/2 * constant. This has to be equal to r^2/R^2, therefore constant = 2/R^2. Thus you have the probability distribution p(r) = r * 2/R^2
Note: Another more intuitive way to think about the problem is to imagine that you are trying to give each circle of radius r a probability density equal to the proportion of the number of points it has on its circumference. Thus a circle which has radius r will have 2 * pi * r "points" on its circumference. The total number of points is pi * R^2. Thus you should give the circle r a probability equal to (2 * pi * r) / (pi * R^2) = 2 * r/R^2. This is much easier to understand and more intuitive, but it's not quite as mathematically sound.
It really depends on what you mean by 'uniformly random'. This is a subtle point and you can read more about it on the wiki page here: http://en.wikipedia.org/wiki/Bertrand_paradox_%28probability%29, where the same problem, giving different interpretations to 'uniformly random' gives different answers!
Depending on how you choose the points, the distribution could vary, even though they are uniformly random in some sense.
It seems like the blog entry is trying to make it uniformly random in the following sense: If you take a sub-circle of the circle, with the same center, then the probability that the point falls in that region is proportional to the area of the region. That, I believe, is attempting to follow the now standard interpretation of 'uniformly random' for 2D regions with areas defined on them: probability of a point falling in any region (with area well defined) is proportional to the area of that region.
Here is my Python code to generate num random points from a circle of radius rad:
import matplotlib.pyplot as plt
import numpy as np
rad = 10
num = 1000
t = np.random.uniform(0.0, 2.0*np.pi, num)
r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
x = r * np.cos(t)
y = r * np.sin(t)
plt.plot(x, y, "ro", ms=1)
plt.axis([-15, 15, -15, 15])
plt.show()
I think that in this case using polar coordinates is a way of complicate the problem, it would be much easier if you pick random points into a square with sides of length 2R and then select the points (x,y) such that x^2+y^2<=R^2.
Solution in Java and the distribution example (2000 points)
public void getRandomPointInCircle() {
double t = 2 * Math.PI * Math.random();
double r = Math.sqrt(Math.random());
double x = r * Math.cos(t);
double y = r * Math.sin(t);
System.out.println(x);
System.out.println(y);
}
based on previus solution https://stackoverflow.com/a/5838055/5224246 from #sigfpe
I used once this method:
This may be totally unoptimized (ie it uses an array of point so its unusable for big circles) but gives random distribution enough. You could skip the creation of the matrix and draw directly if you wish to. The method is to randomize all points in a rectangle that fall inside the circle.
bool[,] getMatrix(System.Drawing.Rectangle r) {
bool[,] matrix = new bool[r.Width, r.Height];
return matrix;
}
void fillMatrix(ref bool[,] matrix, Vector center) {
double radius = center.X;
Random r = new Random();
for (int y = 0; y < matrix.GetLength(0); y++) {
for (int x = 0; x < matrix.GetLength(1); x++)
{
double distance = (center - new Vector(x, y)).Length;
if (distance < radius) {
matrix[x, y] = r.NextDouble() > 0.5;
}
}
}
}
private void drawMatrix(Vector centerPoint, double radius, bool[,] matrix) {
var g = this.CreateGraphics();
Bitmap pixel = new Bitmap(1,1);
pixel.SetPixel(0, 0, Color.Black);
for (int y = 0; y < matrix.GetLength(0); y++)
{
for (int x = 0; x < matrix.GetLength(1); x++)
{
if (matrix[x, y]) {
g.DrawImage(pixel, new PointF((float)(centerPoint.X - radius + x), (float)(centerPoint.Y - radius + y)));
}
}
}
g.Dispose();
}
private void button1_Click(object sender, EventArgs e)
{
System.Drawing.Rectangle r = new System.Drawing.Rectangle(100,100,200,200);
double radius = r.Width / 2;
Vector center = new Vector(r.Left + radius, r.Top + radius);
Vector normalizedCenter = new Vector(radius, radius);
bool[,] matrix = getMatrix(r);
fillMatrix(ref matrix, normalizedCenter);
drawMatrix(center, radius, matrix);
}
First we generate a cdf[x] which is
The probability that a point is less than distance x from the centre of the circle. Assume the circle has a radius of R.
obviously if x is zero then cdf[0] = 0
obviously if x is R then the cdf[R] = 1
obviously if x = r then the cdf[r] = (Pi r^2)/(Pi R^2)
This is because each "small area" on the circle has the same probability of being picked, So the probability is proportionally to the area in question. And the area given a distance x from the centre of the circle is Pi r^2
so cdf[x] = x^2/R^2 because the Pi cancel each other out
we have cdf[x]=x^2/R^2 where x goes from 0 to R
So we solve for x
R^2 cdf[x] = x^2
x = R Sqrt[ cdf[x] ]
We can now replace cdf with a random number from 0 to 1
x = R Sqrt[ RandomReal[{0,1}] ]
Finally
r = R Sqrt[ RandomReal[{0,1}] ];
theta = 360 deg * RandomReal[{0,1}];
{r,theta}
we get the polar coordinates
{0.601168 R, 311.915 deg}
This might help people interested in choosing an algorithm for speed; the fastest method is (probably?) rejection sampling.
Just generate a point within the unit square and reject it until it is inside a circle. E.g (pseudo-code),
def sample(r=1):
while True:
x = random(-1, 1)
y = random(-1, 1)
if x*x + y*y <= 1:
return (x, y) * r
Although it may run more than once or twice sometimes (and it is not constant time or suited for parallel execution), it is much faster because it doesn't use complex formulas like sin or cos.
The area element in a circle is dA=rdr*dphi. That extra factor r destroyed your idea to randomly choose a r and phi. While phi is distributed flat, r is not, but flat in 1/r (i.e. you are more likely to hit the boundary than "the bull's eye").
So to generate points evenly distributed over the circle pick phi from a flat distribution and r from a 1/r distribution.
Alternatively use the Monte Carlo method proposed by Mehrdad.
EDIT
To pick a random r flat in 1/r you could pick a random x from the interval [1/R, infinity] and calculate r=1/x. r is then distributed flat in 1/r.
To calculate a random phi pick a random x from the interval [0, 1] and calculate phi=2*pi*x.
You can also use your intuition.
The area of a circle is pi*r^2
For r=1
This give us an area of pi. Let us assume that we have some kind of function fthat would uniformly distrubute N=10 points inside a circle. The ratio here is 10 / pi
Now we double the area and the number of points
For r=2 and N=20
This gives an area of 4pi and the ratio is now 20/4pi or 10/2pi. The ratio will get smaller and smaller the bigger the radius is, because its growth is quadratic and the N scales linearly.
To fix this we can just say
x = r^2
sqrt(x) = r
If you would generate a vector in polar coordinates like this
length = random_0_1();
angle = random_0_2pi();
More points would land around the center.
length = sqrt(random_0_1());
angle = random_0_2pi();
length is not uniformly distributed anymore, but the vector will now be uniformly distributed.
There is a linear relationship between the radius and the number of points "near" that radius, so he needs to use a radius distribution that is also makes the number of data points near a radius r proportional to r.
I don't know if this question is still open for a new solution with all the answer already given, but I happened to have faced exactly the same question myself. I tried to "reason" with myself for a solution, and I found one. It might be the same thing as some have already suggested here, but anyway here it is:
in order for two elements of the circle's surface to be equal, assuming equal dr's, we must have dtheta1/dtheta2 = r2/r1. Writing expression of the probability for that element as P(r, theta) = P{ r1< r< r1 + dr, theta1< theta< theta + dtheta1} = f(r,theta)*dr*dtheta1, and setting the two probabilities (for r1 and r2) equal, we arrive to (assuming r and theta are independent) f(r1)/r1 = f(r2)/r2 = constant, which gives f(r) = c*r. And the rest, determining the constant c follows from the condition on f(r) being a PDF.
I am still not sure about the exact '(2/R2)×r' but what is apparent is the number of points required to be distributed in given unit 'dr' i.e. increase in r will be proportional to r2 and not r.
check this way...number of points at some angle theta and between r (0.1r to 0.2r) i.e. fraction of the r and number of points between r (0.6r to 0.7r) would be equal if you use standard generation, since the difference is only 0.1r between two intervals. but since area covered between points (0.6r to 0.7r) will be much larger than area covered between 0.1r to 0.2r, the equal number of points will be sparsely spaced in larger area, this I assume you already know, So the function to generate the random points must not be linear but quadratic, (since number of points required to be distributed in given unit 'dr' i.e. increase in r will be proportional to r2 and not r), so in this case it will be inverse of quadratic, since the delta we have (0.1r) in both intervals must be square of some function so it can act as seed value for linear generation of points (since afterwords, this seed is used linearly in sin and cos function), so we know, dr must be quadratic value and to make this seed quadratic, we need to originate this values from square root of r not r itself, I hope this makes it little more clear.
Such a fun problem.
The rationale of the probability of a point being chosen lowering as distance from the axis origin increases is explained multiple times above. We account for that by taking the root of U[0,1].
Here's a general solution for a positive r in Python 3.
import numpy
import math
import matplotlib.pyplot as plt
def sq_point_in_circle(r):
"""
Generate a random point in an r radius circle
centered around the start of the axis
"""
t = 2*math.pi*numpy.random.uniform()
R = (numpy.random.uniform(0,1) ** 0.5) * r
return(R*math.cos(t), R*math.sin(t))
R = 200 # Radius
N = 1000 # Samples
points = numpy.array([sq_point_in_circle(R) for i in range(N)])
plt.scatter(points[:, 0], points[:,1])
A programmer solution:
Create a bit map (a matrix of boolean values). It can be as large as you want.
Draw a circle in that bit map.
Create a lookup table of the circle's points.
Choose a random index in this lookup table.
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;
bool matrix[MATRIX_SIZE][MATRIX_SIZE] = {0};
struct Point { int x; int y; };
Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];
void init()
{
int numberOfOnBits = 0;
for (int x = 0 ; x < MATRIX_SIZE ; ++x)
{
for (int y = 0 ; y < MATRIX_SIZE ; ++y)
{
if (x * x + y * y < RADIUS * RADIUS)
{
matrix[x][y] = true;
loopUpTable[numberOfOnBits].x = x;
loopUpTable[numberOfOnBits].y = y;
++numberOfOnBits;
} // if
} // for
} // for
} // ()
Point choose()
{
int randomIndex = randomInt(numberOfBits);
return loopUpTable[randomIndex];
} // ()
The bitmap is only necessary for the explanation of the logic. This is the code without the bitmap:
const int RADIUS = 64;
const int MATRIX_SIZE = RADIUS * 2;
struct Point { int x; int y; };
Point lookupTable[MATRIX_SIZE * MATRIX_SIZE];
void init()
{
int numberOfOnBits = 0;
for (int x = 0 ; x < MATRIX_SIZE ; ++x)
{
for (int y = 0 ; y < MATRIX_SIZE ; ++y)
{
if (x * x + y * y < RADIUS * RADIUS)
{
loopUpTable[numberOfOnBits].x = x;
loopUpTable[numberOfOnBits].y = y;
++numberOfOnBits;
} // if
} // for
} // for
} // ()
Point choose()
{
int randomIndex = randomInt(numberOfBits);
return loopUpTable[randomIndex];
} // ()
1) Choose a random X between -1 and 1.
var X:Number = Math.random() * 2 - 1;
2) Using the circle formula, calculate the maximum and minimum values of Y given that X and a radius of 1:
var YMin:Number = -Math.sqrt(1 - X * X);
var YMax:Number = Math.sqrt(1 - X * X);
3) Choose a random Y between those extremes:
var Y:Number = Math.random() * (YMax - YMin) + YMin;
4) Incorporate your location and radius values in the final value:
var finalX:Number = X * radius + pos.x;
var finalY:Number = Y * radois + pos.y;
I have three vertices which make up a plane/polygon in 3D Space, v0, v1 & v2.
To calculate barycentric co-ordinates for a 3D point upon this plane I must first project both the plane and point into 2D space.
After trawling the web I have a good understanding of how to calculate barycentric co-ordinates in 2D space, but I am stuck at finding the best way to project my 3D points into a suitable 2D plane.
It was suggested to me that the best way to achieve this was to "drop the axis with the smallest projection". Without testing the area of the polygon formed when projected on each world axis (xy, yz, xz) how can I determine which projection is best (has the largest area), and therefore is most suitable for calculating the most accurate barycentric co-ordinate?
Example of computation of barycentric coordinates in 3D space as requested by the OP. Given:
3D points v0, v1, v2 that define the triangle
3D point p that lies on the plane defined by v0, v1 and v2 and inside the triangle spanned by the same points.
"x" denotes the cross product between two 3D vectors.
"len" denotes the length of a 3D vector.
"u", "v", "w" are the barycentric coordinates belonging to v0, v1 and v2 respectively.
triArea = len((v1 - v0) x (v2 - v0)) * 0.5
u = ( len((v1 - p ) x (v2 - p )) * 0.5 ) / triArea
v = ( len((v0 - p ) x (v2 - p )) * 0.5 ) / triArea
w = ( len((v0 - p ) x (v1 - p )) * 0.5 ) / triArea
=> p == u * v0 + v * v1 + w * v2
The cross product is defined like this:
v0 x v1 := { v0.y * v1.z - v0.z * v1.y,
v0.z * v1.x - v0.x * v1.z,
v0.x * v1.y - v0.y * v1.x }
WARNING - Almost every thing I know about using barycentric coordinates, and using matrices to solve linear equations, was learned last night because I found this question so interesting. So the following may be wrong, wrong, wrong - but some test values I have put in do seem to work.
Guys and girls, please feel free to rip this apart if I screwed up completely - but here goes.
Finding barycentric coords in 3D space (with a little help from Wikipedia)
Given:
v0 = (x0, y0, z0)
v1 = (x1, y1, z1)
v2 = (x2, y2, z2)
p = (xp, yp, zp)
Find the barycentric coordinates:
b0, b1, b2 of point p relative to the triangle defined by v0, v1 and v2
Knowing that:
xp = b0*x0 + b1*x1 + b2*x2
yp = b0*y0 + b1*y1 + b2*y2
zp = b0*z0 + b1*z1 + b2*z2
Which can be written as
[xp] [x0] [x1] [x2]
[yp] = b0*[y0] + b1*[y1] + b2*[y2]
[zp] [z0] [z1] [z2]
or
[xp] [x0 x1 x2] [b0]
[yp] = [y0 y1 y2] . [b1]
[zp] [z0 z1 z2] [b2]
re-arranged as
-1
[b0] [x0 x1 x2] [xp]
[b1] = [y0 y1 y2] . [yp]
[b2] [z0 z1 z2] [zp]
the determinant of the 3x3 matrix is:
det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0)
its adjoint is
[y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1]
[y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2]
[y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0]
giving:
[b0] [y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1] [xp]
[b1] = ( [y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2] . [yp] ) / det
[b2] [y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0] [zp]
If you need to test a number of points against the triangle, stop here. Calculate the above 3x3 matrix once for the triangle (dividing it by the determinant as well), and then dot product that result to each point to get the barycentric coords for each point.
If you are only doing it once per triangle, then here is the above multiplied out (courtesy of Maxima):
b0 = ((x1*y2-x2*y1)*zp+xp*(y1*z2-y2*z1)+yp*(x2*z1-x1*z2)) / det
b1 = ((x2*y0-x0*y2)*zp+xp*(y2*z0-y0*z2)+yp*(x0*z2-x2*z0)) / det
b2 = ((x0*y1-x1*y0)*zp+xp*(y0*z1-y1*z0)+yp*(x1*z0-x0*z1)) / det
That's quite a few additions, subtractions and multiplications - three divisions - but no sqrts or trig functions. It obviously does take longer than the pure 2D calcs, but depending on the complexity of your projection heuristics and calcs, this might end up being the fastest route.
As I mentioned - I have no idea what I'm talking about - but maybe this will work, or maybe someone else can come along and correct it.
Update: Disregard, this approach does not work in all cases
I think I have found a valid solution to this problem.
NB: I require a projection to 2D space rather than working with 3D Barycentric co-ordinates as I am challenged to make the most efficient algorithm possible. The additional overhead incurred by finding a suitable projection plane should still be smaller than the overhead incurred when using more complex operations such as sqrt or sin() cos() functions (I guess I could use lookup tables for sin/cos but this would increase the memory footprint and defeats the purpose of this assignment).
My first attempts found the delta between the min/max values on each axis of the polygon, then eliminated the axis with the smallest delta. However, as suggested by #PeterTaylor there are cases where dropping the axis with the smallest delta, can yeild a straight line rather than a triangle when projected into 2D space. THIS IS BAD.
Therefore my revised solution is as follows...
Find each sub delta on each axis for the polygon { abs(v1.x-v0.x), abs(v2.x-v1.x), abs(v0.x-v2.x) }, this results in 3 scalar values per axis.
Next, multiply these scaler values to compute a score. Repeat this, calculating a score for each axis. (This way any 0 deltas force the score to 0, automatically eliminating this axis, avoiding triangle degeneration)
Eliminate the axis with the lowest score to form the projection, e.g. If the lowest score is in the x-axis, project onto the y-z plane.
I have not had time to unit test this approach but after preliminary tests it seems to work rather well. I would be eager to know if this is in-fact the best approach?
After much discussion there is actually a pretty simple way to solve the original problem of knowing which axis to drop when projecting to 2D space. The answer is described in 3D Math Primer for Graphics and Game Development as follows...
"A solution to this dilemma is to
choose the plane of projection so as
to maximize the area of the projected
triangle. This can be done by
examining the plane normal; the
coordinate that has the largest
absolute value is the coordinate that
we will discard. For example, if the
normal is [–1, 0, 0], then we would
discard the x values of the vertices
and p, projecting onto the yz plane."
My original solution which involved computing a score per axis (using sub deltas) is flawed as it is possible to generate a zero score for all three axis, in which case the axis to drop remains undetermined.
Using the normal of the collision plane (which can be precomputed for efficiency) to determine which axis to drop when projecting into 2D is therefore the best approach.
To project a point p onto the plane defined by the vertices v0, v1 & v2 you must calculate a rotation matrix. Let us call the projected point pd
e1 = v1-v0
e2 = v2-v0
r = normalise(e1)
n = normalise(cross(e1,e2))
u = normalise(n X r)
temp = p-v0
pd.x = dot(temp, r)
pd.y = dot(temp, u)
pd.z = dot(temp, n)
Now pd can be projected onto the plane by setting pd.z=0
Also pd.z is the distance between the point and the plane defined by the 3 triangles. i.e. if the projected point lies within the triangle, pd.z is the distance to the triangle.
Another point to note above is that after rotation and projection onto this plane, the vertex v0 lies is at the origin and v1 lies along the x axis.
HTH
I'm not sure that the suggestion is actually the best one. It's not too hard to project to the plane containing the triangle. I assume here that p is actually in that plane.
Let d1 = sqrt((v1-v0).(v1-v0)) - i.e. the distance v0-v1.
Similarly let d2 = sqrt((v2-v0).(v2-v0))
v0 -> (0,0)
v1 -> (d1, 0)
What about v2? Well, you know the distance v0-v2 = d2. All you need is the angle v1-v0-v2. (v1-v0).(v2-v0) = d1 d2 cos(theta). Wlog you can take v2 as having positive y.
Then apply a similar process to p, with one exception: you can't necessarily take it as having positive y. Instead you can check whether it has the same sign of y as v2 by taking the sign of (v1-v0)x(v2-v0) . (v1-v0)x(p-v0).
As an alternative solution, you could use a linear algebra solver on the matrix equation for the tetrahedral case, taking as the fourth vertex of the tetrahedron v0 + (v1-v0)x(v2-v0) and normalising if necessary.
You shouldn't need to determine the optimal area to find a decent projection.
It's not strictly necessary to find the "best" projection at all, just one that's good enough, and that doesn't degenerate to a line when projected into 2D.
EDIT - algorithm deleted due to degenerate case I hadn't thought of