I wish to randomly and uniformly generate points on a cylinder and a cone (separately). The cylinder is defined by its center, its radius and height. Same specifications for the cone. I am able to get the bounding box for each shape so I was thinking of generating points within the bounding box. However, I'm not sure how to project them onto the cylinder/cone or if this is the best idea.
Any suggestions?
Thanks.
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.
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.
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.
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 )
Related
I have program to write in my C++ course. In coordinate plane we have circle with radius R.Circle center is at the point (xc,yc). Also I have n point with coordinates( for example n=2 and coordinates is (1;1) (-1;-1). I need to calculate how many points there is in a circle, on it and outside of it.. Please help :)
You need to calculate distance between circle center and the point. The formula of distance between two points is:
d = sqrt( (xc - x)^2 + (yc - y)^2 )
where: (xc, yc) - coordinates of circle center, (x, y) - coordinates of your point.
if the distance is greater then radius then point is outside the circle (d > R)
Then you need repeat this for n points and remember how many of them are inside and how many are outside. and that's all.
Now you have an algorithm you can try to code it!
Simple math...
Surface of a square is calculated by S = pi*r^2
given r in pixels, S would come in pixels...
it is worthy to note, that this method is approximation, because it is not over a discrete plane
In order to be more precise (though, considerably slower):
refer to #Sandro answer, and check the distance to each point on your plane..
with two optimizations that you may want to consider:
exclude the outer Bounding box
You need to check only the pixels x in [xc - r, xc + r] U y in [yc - r, yc + r]
automatically include inscribed square
You can include every pixel in x in (xc - sqrt(2)r, xc + sqrt(2)r) U (yc - sqrt(2)r, yc + sqrt(2)r)
references:
Circles Inscribed in Squares
Squares Circumscribed by Circles
Equation of a circle: R^2 = (xc - x)^2 + (yc-y)^2 where (xc, yc) are coordinates of circle center. (x, y) - coordinates of point, R - radius. So:
double distance = sqrt((xc - x)*(xc - x) + (yc-y)*(yc-y));
if (distance < R)
{
// inside
}
else if(distance > R)
{
// outside
}
else
{
// on circle
}
I want to find if a vertex is inside of a cube in a C++ program.
Take this example, I want to find all vertices of the torus that lie inside of the cube.
Image
How would I go on doing this, knowing that my cube is just a list of points to start with (I'm parsing an .obj file)
For example, my cube vertices:
v -56.269790649414 -100.226547241211 -29.616094589233
v 3.730209350586 -100.226547241211 -29.616094589233
v -56.269790649414 -40.226547241211 -29.616094589233
v 3.730209350586 -40.226547241211 -29.616094589233
v -56.269790649414 -100.226547241211 30.383905410767
v 3.730209350586 -100.226547241211 30.383905410767
v -56.269790649414 -40.226547241211 30.383905410767
v 3.730209350586 -40.226547241211 30.383905410767
What are the best practices/algorithms to achieve this (raycasting?)
For arbitrary mesh (not just the cube), you can generate a ray from the point you want to test and see how many times the ray intersects with your mesh. For even number of intersections (including zero) => point is outside, for odd number of intersections => point is inside. But it could be faster if you can bring your cube to origin and align it along the axes. Then it's just a matter or three ifs.
Apparently your cube is axis-parallel, so it is sufficient to check whether the vertex to test lies in the intersection of the slice of the parellel side planes. To put it differently, an axis-parallel cube is its own bounding box. Let
x_max = maximum x-coordinate of the cube
x_min = minimum x-coordinate of the cube
y_max = maximum y-coordinate of the cube
y_min = minimum y-coordinate of the cube
z_max = maximum z-coordinate of the cube
Z_min = minimum z-coordinate of the cube
then a point (x,y,z) is contained in the cube if and only if
x_min <= x <= x_max && y_min <= y <= y_max && z_min <= z <= Z_max
However things are more complicated if the cube is actually not axis-parallel.
Ok.... so I made a quick diagram to sorta explain what I'm hoping to accomplish. Sadly math is not my forte and I'm hoping one of you wizards can give me the correct formulas :) This is for a c++ program, but really I'm looking for the formulas rather than c++ code.
Ok, now basically, the red circle is our 0,0 point, where I'm standing. The blue circle is 300 units above us and at what I would assume is a 0 degree's angle. I want to know, how I can find a find the x,y for a point in this chart using the angle of my choice as well as a certain distance of my choice.
I would want to know how to find the x,y of the green circle which is lets say 225 degrees and 500 units away.
So I assume I have to figure out a way to transpose a circle that is 500 units away from 0,0 at all points than pick a place on that circle based on the angle I want? But yeah no idea where to go from there.
A point on a plane can be expressed in two main mathematical representations, cartesian (thus x,y) and polar : using a distance from the center and an angle. Typically r and a greek letter, but let's use w.
Definitions
Under common conventions, r is the distance from the center (0,0) to your point, and
angles are measured going counterclockwise (for positive values, clockwise for negative), with the 0 being the horizontal on the right hand side.
Remarks
Note a few things about angles in polar representations :
angles can be expressed with radians as well, with π being the same angle as 180°, thus π/2 90° and so on. π=3.14 (approx.) is defined by 2π=the perimeter of a circle of radius 1.
angles can be represented modulo a full circle. A full circle is either 2π or 360°, thus +90° is the same as -270°, and +180° and -180° are the same, as well as 3π/4 and -5π/4, 2π and 0, 360° and 0°, etc. You can consider angles between [-π,π] (that is [-180,180]) or [0,2π] (i.e. [0,360]), or not restrain them at all, it doesn't matter.
when your point is in the center (r=0) then the angle w is not really defined.
r is by definition always positive. If r is negative, you can change its sign and add half a turn (π or 180°) to get coordinates for the same point.
Points on your graph
red : x=0, y=0 or r=0 w= any value
blue : x=0, y=300 or r=300 and w=90°
green : x=-400, y=-400 or r=-565 and w=225° (approximate values, I didn't do the actual measurements)
Note that for the blue point you can have w=-270°, and for the green w=-135°, etc.
Going from one representation to the other
Finally, you need trigonometry formulas to go back and forth between representations. The easier transformation is from polar to cartesian :
x=r*cos(w)
y=r*sin(w)
Since cos²+sin²=1, pythagoras, and so on, you can see that x² + y² = r²cos²(w) + r²sin²(w) = r², thus to get r, use :
r=sqrt(x²+y²)
And finally to get the angle, we use cos/sin = tan where tan is another trigonometry function. From y/x = r sin(w) / (r cos(w)) = tan(w), you get :
w = arctan(y/x) [mod π]
tan is a function modulo π, instead of 2π. arctan simply means the inverse of the function tan, and is sometimes written tan^-1 or atan.
By inverting the tangent, you get a result betweeen -π/2 and π/2 (or -90° and 90°) : you need to eventually add π to your result. This is done for angles between [π/2,π] and [-π,π/2] ([90,180] and [-180,-90]). These values are caracterized by the sign of the cos : since x = r cos(w) you know x is negative on all these angles. Try looking where these angles are on your graph, it's really straightforward. Thus :
w = arctan(y/x) + (π if x < 0)
Finally, you can not divide by x if it is 0. In that corner case, you have
if y > 0, w = π/2
if y < 0, w = -π/2
What is seems is that given polar coordinates, you want to obtain Cartesian coordinates from this. It's some simple mathematics and should be easy to do.
to convert polar(r, O) coordinates to cartesian(x, y) coordinates
x = r * cos(O)
y = r * sin(O)
where O is theta, not zero
reference: http://www.mathsisfun.com/polar-cartesian-coordinates.html
Does anyone know some algorithm to calculate the number of sides required to approximate a circle using polygon, if radius, r of the circle and maximum departure of the polygon from circularity, D is given? I really need to find the number of sides as I need to draw the approximated circle in OpenGL.
Also, we have the resolution of the screen in NDC coordinates per pixel given by P and solving D = P/2, we could guarantee that our circle is within half-pixel of accuracy.
What you're describing here is effectively a quality factor, which often goes hand-in-hand with error estimates.
A common way we handle this is to calculate the error for a a small portion of the circumference of the circle. The most trivial is to determine the difference in arc length of a slice of the circle, compared to a line segment joining the same two points on the circumference. You could use more effective measures, like difference in area, radius, etc, but this method should be adequate.
Think of an octagon, circumscribed with a perfect circle. In this case, the error is the difference in length of the line between two adjacent points on the octagon, and the arc length of the circle joining those two points.
The arc length is easy enough to calculate: PI * r * theta, where r is your radius, and theta is the angle, in radians, between the two points, assuming you draw lines from each of these points to the center of the circle/polygon. For a closed polygon with n sides, the angle is just (2*PI/n) radians. Let the arc length corresponding to this value of n be equal to A, ie A=2*PI*r/n.
The line length between the two points is easily calculated. Just divide your circle into n isosceles triangles, and each of those into two right-triangles. You know the angle in each right triangle is theta/2 = (2*PI/n)/2 = (PI/n), and the hypotenuse is r. So, you get your equation of sin(PI/n)=x/r, where x is half the length of the line segment joining two adjacent points on your circumscribed polygon. Let this value be B (ie: B=2x, so B=2*r*sin(PI/n)).
Now, just calculate the relative error, E = |A-B| / A (ie: |TrueValue-ApproxValue|/|TrueValue|), and you get a nice little percentage, represented in decimal, of your error vector. You can use the above equations to set a constraint on E (ie: it cannot be greater than some value, say, 1.05), in order for it to "look good".
So, you could write a function that calculates A, B, and E from the above equations, and loop through values of n, and have it stop looping when the calculated value of E is less than your threshold.
I would say that you need to set the number of sides depending on two variables the radius and the zoom (if you allow zoom)
A circle or radius 20 pixels can look ok with 32 to 56 sides, but if you use the same number of sided for a radios of 200 pixels that number of sides will not be enough
numberOfSides = radius * 3
If you allow zoom in and out you will need to do something like this
numberOfSides = radiusOfPaintedCircle * 3
When you zoom in radiusOfPaintedCircle will be bigger that the "property" of the circle being drawn
I've got an algorithm to draw a circle using fixed function opengl, maybe it'll help?
It's hard to know what you mean when you say you want to "approximate a circle using polygon"
You'll notice in my algorithm below that I don't calculate the number of lines needed to draw the circle, I just iterate between 0 .. 2Pi, stepping the angle by 0.1 each time, drawing a line with glVertex2f to that point on the circle, from the previous point.
void Circle::Render()
{
glLoadIdentity();
glPushMatrix();
glBegin(GL_LINES);
glColor3f(_vColour._x, _vColour._y, _vColour._z);
glVertex3f(_State._position._x, _State._position._y, 0);
glVertex3f(
(_State._position._x + (sinf(_State._angle)*_rRadius)),
(_State._position._y + (cosf(_State._angle)*_rRadius)),
0
);
glEnd();
glTranslatef(_State._position._x, _State._position._y, 0);
glBegin(GL_LINE_LOOP);
glColor3f(_vColour._x, _vColour._y, _vColour._z);
for(float angle = 0.0f; angle < g_k2Pi; angle += 0.1f)
glVertex2f(sinf(angle)*_rRadius, cosf(angle)*_rRadius);
glEnd();
glPopMatrix();
}
Consider a simple convex polygon in 2D Cartesian space. If given a list of vertex coordinates sorted in a counter-clockwise orientation like this [[x0, y0], ..., [xn, yn]]. How could you compute the center of the polygon (the point inside the polygon that is equidistant to all vertices)?
Also consider a second case where the polygon is placed in 3D Cartesian space and its normal vector is not parallel to any of the Cartesian axes. How could you compute the center, without rotating the polygon?
I can read C/C++, Fortran, MATLAB and Python, however any pseudo-code is also well appreciated.
EDIT
I now realise that my question was not well-posed. I am sorry for that. It appears that what I was looking for is the centroid of the polygon (i.e. the point on which a cardboard cut-out would balance while assuming uniform density and a uniform gravity field).
You definition of center doesn't make sense in general.
To see this just draw three non-aligned points on a plane and compute the one an only circle that passes for all three points. Clearly your center of the triangle must be the center of this circle.
Now draw a fourth point that doesn't lie on the circle and form the four sided polygon. What is the center? There is no point in the plane that is equidistant from all vertices.
Note also that even in case of triangles using the point equidistant from the vertices can give you points outside and far away from the polygon and is also numerically unstable (given any ε>0 and M>0 you can always build a triangle in which a specific movement of a vertex by a distance of less than ε moves the center by a distance greater than M).
Commonly used "centers" that are simple to compute are the average of all vertices, the average of the boundary, the center of mass or even just the center of the axis-aligned bounding box. All of them can however fall outside the polygon if the polygon is not convex, but in your case they may work.
The simplest reasonable one (because it doesn't depends on the coordinate system) is the barycenter of the vertices (code in Python):
xc = sum(x for (x, y) in points) / len(points)
yc = sum(y for (x, y) in points) / len(points)
something bad about it it's that just splitting one side of the polygon gives you a different center (in other words it depends on the vertices and not on the set of points bounded by the polygon). The simplest that depends on the polygon is IMO the barycenter of the boundary:
sx = sy = sL = 0
for i in range(len(points)): # counts from 0 to len(points)-1
x0, y0 = points[i - 1] # in Python points[-1] is last element of points
x1, y1 = points[i]
L = ((x1 - x0)**2 + (y1 - y0)**2) ** 0.5
sx += (x0 + x1)/2 * L
sy += (y0 + y1)/2 * L
sL += L
xc = sx / sL
yc = sy / sL
For both of them the extension to 3d is trivial... just add z using the same formulas.
In the case of a general (not necessarily convex, not necessarily simply connected) polygon a "center" that I found useful but that is not trivial to compute is the (an) inner point that is at a maximum distance from the boundary (in other words a "most inner" point).
In this case I resorted to use a discrete (bitmap) representation and a gaussian distance transform.
First of all for a polygon, the centroid may not always imply equidistant lengths from the centroid to the vertices. In most cases this is probably NOT true. That being said, you can find the centroid simply by finding the mean of your x coordinates and the mean of your y coordinates. In Matlab: centroidx = mean(xcoords) and centroidy = mean(ycoords) are the coordinates of the centroid. See this if you really need more.