Imagine that we cut a piece of pie with known fixed height (H). We cut it in such a way that the upper arc has angle A1 and the bottom arc has angle A2. However, we also know that the upper arc has two radii (R1 and R2) and the bottom arc has two different radii (R3 and R4). These four radii are not connected anyhow to each other (might be elliptic axis, but might be total random).
Technically, if not thinking about pies, we have two polygons (with the same number of points), with mass centers a bit different from each other. Taking two points from the upper polygon, we assume they form a local elliptic arc with two radii and angle A1. (The other arc from the same polygon will most likely have different radii values and angle).
We can take two points from the lower polygon which will correspond to the two points of the upper polygon (typically, using index values) and form the lower local elliptic arc with another angle and radii values.
Thus the question is how to calculate the volume of this piece? Again, two upper radii (R1 and R2), two bottom radii (R3 and R4), fixed height (H) and two angles (A1 and A2). Note: the centers of the upper and bottom parts (essentially, polygons) might be different.
Thanks in advance for help
This approximation might help (assuming A1, A2 to be given in radians):
area of top "sector" A_top ~ (R1 + R2) * A1 / 4
area of bottom "sector" A_bot ~ (R3 + R4) * A2 / 4
volume of piece of pie V ~ (A_top + A_bot) * H / 2
Related
I am trying to draw a rotated ellipse not centered at the origin (in c++).
so far my code "works":
for (double i = 0; i <= 360; i = i + 1) {
theta = i*pi / 180;
x = (polygonList[compt]->a_coeff / 2) * sin(theta) + polygonList[compt]->centroid->datapointx;
y = (polygonList[compt]->b_coeff / 2) * cos(theta) + polygonList[compt]->centroid->datapointy;
xTmp = (x - polygonList[compt]->centroid->datapointx)* cos(angle1) - (y - polygonList[compt]->centroid->datapointy)*sin(angle1) + polygonList[compt]->centroid->datapointx;
yTmp = (x - polygonList[compt]->centroid->datapointx)* sin(angle1) + (y - polygonList[compt]->centroid->datapointy)*cos(angle1) + polygonList[compt]->centroid->datapointy;
}
PolygonList is a list of "bloc" which will be replaced by an ellipse of same area.
My issue is that the angles are not quite exact, as if I had to put a protractor that'd fit the shape of my ellipse, the protractor would obviously get squeezed, and so would be the angles (is that clear ?)
Here is an example: I am trying to set a point on the top ellipse (E1) which would be lying on a line drawn between the centroid of E1, and any point on the second ellipse (E2).On this example, the point on E2 lies at an angle of ~220-230 degree. I am able to catch this angle, the angle seems ok.
The problem is that if I try to project this point on E1 by using this angle of ~225 degree, I end up on the second red circle on top. it looks like my angle is now ~265 degree, but in fact, if I shape the protractor to fit in my ellipse, I get the right angle (~225) ,cf img 2)
it is a bit hard to see the angle on that re-shaped protractor, but it does show ~225 degree.
My conclusion is that the ellipse is drawn like if I had to drew a circle and then I'd compress it, which changes the distance between the angles.
Could someone tell me how I could fix that ?
PS: to draw those ellipses I just use a for loop which plots a dot at every angle (from 0 to 360). we clearly see on the first picture that the distance between the dots are different whether we are at 0 or at 90 degree.
your parametrisation is exactly that, a circle is a case of ellipse with both axes are equal. It sounds like you need use rational representation of ellipse instead of standard: https://en.m.wikipedia.org/wiki/Ellipse
So, I've asked the question above so that I could find a possible overlap between 2 ellipses by checking the distance between any point on E2 and its projection on E1: if the distance between the centroid of E1 and the projected dot on E1 is larger than the distance between the centroid of E1 to a dot on E2 I'll assume an overlap. I reckon this solution has never been tried (or I haven't search enough) and should work fine. But before working I needed to get those angles right.
I have found a way to avoid using angles and projected dots, by checking the foci:
the sum of the distance between the focus A and B to any point around an axis is constant (let's call it DE1 for E1).
I then check the distance between my foci and any point on E2. If that distance becomes less than DE1, I'll assume a connection.
So far it seems to work fine :)
I'll put that here for anyone in need.
Flo
I have coordinates between two points on the map. There are tools for calculating distance between them, but I want to find horizontal and vertical distance between the two places. Can someone help please?
Lets say you points A(x1/y1) and B(x2/y2).
The horizontal and vertical distances between the two are the differences of their coordinates:
x12 = x2 - x1
y12 = y2 - y1
Addition:
The total distance is
d12 = sqrt(y122 + x122)
= sqrt( (y2 - y1)2 + (x2 - x1)2)
where sqrt means "Square Root"
Let's say your 2 known points A and B have latitude and longitude latA, longA and latB, longB.
Now you could introduce two additional points C and D with latC = latA, longC = longB, and latD = latB, longD = longA, so the points A, B, C, D form a rectangle on the earth's surface.
Now you can simply use distanceBetween(A, C) and distanceBetween(A, D) to get the required distances.
Copied from: https://stackoverflow.com/a/62857233/5660341
On the northern hemisphere two positions a and b would look a bit like:
a--+
/ \
/ \
+--------b
So there is a common vertical distance, but a slightly different horizontal distance.
The shortest travel would be horizontally from a (greatest and then vertical to b.
With school math and knowing the zero-height (w.r.t. sea level) ellipse going through both poles you can easily calculate the three distances.
There are sufficient sites, search for longitude, latitude, haversine formula.
There are sufficient simplifications, around, and also one point may be on the northern and the other on the southern hemisphere. And with large values it might be better to horizontally walk left from a to the +. So you have to really dive into the calculation.
I would not dare to give an actual formula here.
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.
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 )