uniform generation of 3D points on cylinder/cone

为君一笑 提交于 2019-12-05 08:11:29

The cylinder case is trivial. If the cylinder of radius r > 0 and height h > 0 is the image of (x, y, z) = (r cos φ, r sin φ, z) on φ ∈ [0, 2π[ and z ∈ [-h/2, h/2], then simply choose φ and z randomly on these intervals. Of course one can simply parametrise the cone as well using the standard parametrisation, but then the area element will not be constant on the parameter plane, and so the distribution of points will not be random. Thus you need to find a different parametrisation. I have discussed this topic in detail for a sphere at my AlgoSim site.

It would be simpler to generate the points directly on the cylinder or cone.

It's been a while since I did this, but parametrise the axis of the cylinder and then for each point parametrise the circle at that height. This will create points on the surface. The radius of the circle is the radius of the cylinder.

For the cone you need to reduce the radius of the circle as you move from the base to the apex.

One way to think of this is that both the cylinder and the cone can be unwrapped into flat surfaces - just cut each one with a straight line from top to bottom.

The cylinder unwraps to a rectangle (if you're including the top and bottom, then add a couple of disks).

The cone unwraps to a triangle with a curved bottom that is the arc of a circle (if you're including the base of the cone, then add a disk).

It's easy enough to embed these flat surfaces inside a rectangle R on the xy plane. Generate uniformly distributed points in R, and whenever they are inside the flat surfaces, map them back to the original surfaces.

Watch out for some of the other answers here which try to co-ordinatize a cone in terms of angle and height. Although the points will be uniformly distributed with respect to angle and height, they will not be uniformly distributed w.r.t. area. They will be more densely distributed at the tip.

Let a point be defined by coordinates r, a, h, where r is the "radius" (distance from the vertical axis passing from the center), a is the angle as in polar coordinates, and h is its height.

For the cylinder (radius R and height H): choose independently

  • a uniform in [0, 2pi),
  • h uniform in [0, H], and
  • r with a "triangular density": f(r) = 2 r / R if 0 <= r <= R, 0 otherwise (the density at r should be proportional to the length of the circumference of radius r).

It should not be difficult to sample from such triangular distribution, since its cumulative distribution (a quadratic monomial) is easily invertible (see this article). Also, this answer is based on intuition, but it should not be difficult to prove that the distribution you obtain on the cylinder is uniform.

For the cone (radius R and height H): choose

  • a uniform in [0, 2pi),
  • h with a density made with a segment of parabola: f(h) = 3 (H - h)^2 / H^3 if 0 <= h <= H, 0 otherwise (the density at h should be proportional to the area of the circular section at height h),
  • let r( h ) = (H - h) R / H (the radius of the section at height h); then choose r with a "triangular distribution" f(r) = 2 r / r( h ) if 0 <= r <= r( h ), 0 otherwise.

Again, sampling h should be easy, since the cumulative distribution is easily invertible.

EDIT. If you mean to generate points on the surface of the shapes, then the solution is simpler:

Cylinder: choose

  • a uniform in [0, 2pi),
  • h uniform in [0, H],
  • r = R.

Cone: choose

  • a uniform in [0, 2pi),
  • h with a triangular density: f(h) = 2 (H - h) / H^2 if 0 <= h <= H, 0 otherwise (the density at h should be proportional to the length of the circumference at height h).
  • r = r( h ) = (H - h) R / H = radius at height h.

Other answers have already covered the cylinder case pretty well. For the cone, things are a bit more difficult. To maintain a constant density of points, you need to compensate for the change in radius.

To do that, you can start by picking a distance between the points. As you move along the axis of the cone, you compute the circumference at that height, then divide the circumference the linear distance between the points to get the number of points. You then divide 2pi radians (or 360 degrees, or whatever) by the number of points to get the angular distance for that radius.

Depending on the accuracy you need, you can keep track of the remainder from one circle as you're computing the next circle. For example, if you have two circles in a row that work out to needing xxx.4 points, you'd round each down if looked at in isolation -- but looking at them together, you have xxx.8 points, so you should round one down and the other up to keep the overall density as close as possible to the correct value.

Note that although it's not as obvious, the latter can apply to the cylinder as well -- you'll typically have some rounding in distributing each circle of points.

To put those answers in pseudocode:

For a cylinder, given cylinderRadius and cylinderHeight:

angle = random number between 0 & 360

x = cos(pi/180*angle)*cylinderRadius
y = sin(pi/180*angle)*cylinderRadius
z = random number between 0 and cylinderHeight.

For a cone, given coneRadius, coneHeight:

angle = random number between 0 & 360

z = random number between 0 and coneHeight

thisRadius = coneRadius * (1-(z/coneHeight)); //This gives a decreasing radius as height increases.

x = cos(pi/180*angle)*thisRadius
y = sin(pi/180*angle)*thisRadius

Each point (x,y,z) will lie on the cylinder/cone. Generate enough of these points and you can spawn particles on the surface of a cylinder/cone, but it may not make an exactly uniform distribution...

For uniform points on a circle or cone of radius R, and height/elevation H:

generate:
  angle= uniform_random(0,2*pi)
  value= uniform_random(0,1)

in either case, let:
  r= R * sqrt(value)

then (using separate random numbers for each):
  circle_point= point3d( r*cos(angle), r*sin(angle), H )
or:
  cone_point= point3d( r*cos(angle), r*sin(angle), r*H )

Note that if you want a base on your cone, you will need to do it separately from the curved shape. To make sure the density of points is the same for the different parts, an easy way is to calculate the areas of the parts and generate a proportional number of points for each part.

The sqrt(value) is what makes sure the density of your random points is uniform. As other questions have mentioned, you want a triangular distribution for this; taking the sqrt() turns the uniform distribution on [0,1) into a triangular one.

For a cylinder you don't want the sqrt(); the curved part is:

  cylinder_point= point3d( R*cos(angle), R*sin(angle), H*value )
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!