I am trying a couple of tutorials from http://nehe.gamedev.net, in order to learn openGL programming, I would like to position spheres along a Bezier curve such that they appear as a string of pearls. how can I position such spheres along the curve. I am drawing the curve using de Casteljau's algorithm and hence can get the XYZ points on the curve.
If your spheres are small enough relative to the overall length of the Bezier curve, you can just position your spheres at even intervals to get an appearance similar to a string of pearls. (If the spheres are relatively large then you'll have to start worrying about sphere overlap more -- not an easy problem, and probably not very instructive for learning OpenGL.)
The parameter value t of a Bezier curve varies from 0 to 1. To evaluate your Bezier curve at 10 locations (the ends and eight interior points) you can do something like this:
for( int i = 0; i <= 9; ++i )
{
double t = i / 9.0;
double x, y;
EvalBezier( t, x, y );
DrawSphere( x, y, radius );
}
Where EvalBezier( t, x, y ) fills in (x,y) for a given t. Just pick radius to give you a pleasing result. If you want to try to pick radius automatically, just use half the minimum distance from the point i to points i-1 and i+1 as a rough estimate. If you do this, remember to handle the end points specially, using either only the next or previous points (whichever you have).
Related
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'm looking for a math formula that on a graph plotting Y as a function of X, before a specified starting point (a value of X, or even better, X and Y coordinates) will have a certain slope, then after that it will draw an arc of a specified radius that will end when it reaches a second specified slope, and from the point on will be another straight line of that second slope.
I'm am aware that because it's Y as a function of X, the slope parameters would need to be bigger than exactly -90 and smaller than exactly 90 degrees; i'm not worried about any misbehavior at (or beyond) those extremes.
Actually, i would be even happier with a formula that takes a starting and ending points (2d coordinates), and starting and ending slopes; and will have two arcs in between (with a straight line between them when needed), connecting the two straight lines seamlessly (obviously the X of the ending point needs to be bigger than the X for the starting point; i don't care what happens when that isn't the case). But i imagine such a formula might be much harder to come up with than what i asked first.
ps: by "arc" i mean segment of a circle; as in, if both axes of the graph have the same scale, the arcs will have the correct aspect ratio for a circle of the same radius.
Well I see it like this:
compute P0
as intersection of lines A + t*dA and B - t*dB
compute P1 (center of circle)
it is intersection of translated lines A->P0 and B->P0 perpendicular by radius r. There are 2 possibilities so choose the right one (which leads to less angle of circular part).
compute P2,P3
just an intersection between lines A-P0 and B-P0 and perpendicular line from P1 to it
the curve
// some constants first
da=P2-A;
db=B-P3;
a2=atan2(P2.x-P1.x,P2.y-P1.y);
a3=atan2(P3.x-P1.x,P3.y-P1.y);
if (a2>a3) a3-=M_PI*2.0;
dang=a3-a2;
// now (x,y)=curve(t) ... where t = <0,3>
if (t<=1.0)
{
x=A.x+t*da.x;
y=A.y+t*da.y;
}
else if (t<=2.0)
{
t=a2+((t-1.0)*dang);
x=P1.x+r*cos(t);
y=P1.y+r*sin(t);
}
else
{
t=t-2.0;
x=P3.x+t*db.x;
y=P3.y+t*db.y;
}
I'm learning Unity3d + some basic maths I've forgotten by messing around.
Heres what I'm doing now..
As you can probably tell the sides of this shape form a parabola.
The distance they are out from the centre is the base radius + the height squared * by a constant (0.05 in this image)
The code generating this is very simple..
for (int changer = 1; changer > -2; changer-=2) {
Vector3 newPos = new Vector3(
transform.position.x
,transform.position.y + currentheight*changer
,transform.position.z - RadiusAtZero -(Mathf.Pow(currentheight,2)*CurveMultiplier)
);
var newFleck = Instantiate(Fleck, newPos, Quaternion.identity)as GameObject;
newFleck.transform.RotateAround(transform.position,Vector3.up,angle*changer);
FleckList.Add(newFleck );
}
Btw the for loop and 'changer' mirror everything so 'currentheight' is really just the distance from the centreline of the parabola.
Anyway I'd like to make the cubes (or flecks as I've called them) be angled so that they are tangentional to the parabola I have made.
I need to determine the angle of a tangent to the parabola at particular point.
I found this
to find the line tangent to y=x^2 -3 at (1, -2) we can simultaneously solve
y=x^2 -3 and y+2=m(x-1) and set the discriminant equal to zero
But I dont know how to implement this. Also I reckon my 'CurveMultiplier' constant makes my parabola equation different from that one.
Can someone write some code that determines the angle? (and also maybe explain it)
Update.
Here is fixed version using the derivative of the equation. (Also I have changed from boxes to tetrahedrons and few other superficial things)
The easiest solution is to use a derivative for the parabolic equation.
In your picture then I'll assume Y is vertical, X horizontal, and Z in/out of the screen. Then the parabola being rotated, based upon your description, is:
f(h) = 0.05*h^2 + R
(h is height, R is base radius). If you imagine a plane containing the Y axis, you can rotate the plane around the Y axis at any angle and the dual parabola looks the same.
The derivative of a parabolic equation of the form f(x) = C*h^2 + R is f'(x) = 2*C*h, which is the slope of the tangent at h. In this specific case, that would be:
f'(h) = 0.1*h
Since the cross-sectional plane has an angle relative to X and Z axes, then that tangent will also have the same angular component (you have a rotated parabola).
Depending upon the units given for the constants in f(h), particularly the 0.05 value, you may have to adjust this for the correct results.
I have some point on a 2D grid (x, y) and I need to find all points that are n distance away from that point. The way I'm measuring distance is by using the distance formula between the two points. Anyone know how to do this?
Edit: Just for reference, what I'm trying to do is to write some AI path finding that will maintain some distance away from a target in a system that uses grid based locations. Currently I'm using A* path finding, but I'm not sure if that matters or makes a difference since I'm kind of new to this stuff.
Here's what I would do:
First filter out all points that are further than D on either x or y. These are certainly outside the circle of radius D. This is a much simpler computation, and it can quickly eliminate a lot of work. This is a outer bounding-box optimization.
You can also use an inner bounding-box optimization. If the points are closer than D * sqrt(2)/2 on either x or y, then they're certainly within the circle of radius D. This is also cheaper than calculating the distance formula.
Then you have a smaller number of candidate points that may be within the circle of radius D. For these, use the distance formula. Remember that if D = sqrt(Δx2+Δy2), then D2 = Δx2+Δy2.
So you can skip the cost of calculating square root.
So in pseudocode, you could do the following:
for each point
begin
if test 1 indicates the point is outside the outer bounding box,
then skip this point
if test 2 indicates the point is inside the inner bounding box,
then keep this point
if test 3 indicates the point is inside the radius of the circle,
then keep this point
end
This problem is known as range query. The brute force solution is just as you described: computed the distance of all points from the reference point and return those whose distance is less than the desired range value.
The brute force algorithm is O(N^2). There are, however, more efficient algorithms that employ spatial indexes to reduce algorithm complexity and the number of distance calculations. For example, you can use a R-Tree to index your points.
Its called nearest neighbor search. More at http://en.wikipedia.org/wiki/Nearest_neighbor_search
There are open libraries for that. I have used one written for C and recommend it: http://www.cs.umd.edu/~mount/ANN/. ANN stands for Approximate Nearest Neighbor, however, you can turn the approximation off and find the exact nearest neighbors.
This wouldn't use the distance formula, but if you're looking for points exactly n distance away, perhaps you could use sin/cos?
In pseudocode:
for degrees in range(360):
x = cos(degrees) * n
y = sin(degrees) * n
print x, y
That would print every point n away in 360 degree increments.
Java implementation:
public static Set<Point> findNearbyPoints(Set<Point> pts, Point centerPt, double radius) {
Set<Point> nearbyPtsSet = new HashSet<Point>();
double innerBound = radius * (Math.sqrt(2.0) / 2.0);
double radiusSq = radius * radius;
for (Point pt : pts) {
double xDist = Math.abs(centerPt.x - pt.x);
double yDist = Math.abs(centerPt.y - pt.y);
if (xDist > radius || yDist > radius)
continue;
if (xDist > innerBound || yDist > innerBound)
continue;
if (distSq(centerPt, pt) < radiusSq)
nearbyPtsSet.add(pt);
}
return nearbyPtsSet;
}
Say I have an arbitrary set of latitude and longitude pairs representing points on some simple, closed curve. In Cartesian space I could easily calculate the area enclosed by such a curve using Green's Theorem. What is the analogous approach to calculating the area on the surface of a sphere? I guess what I am after is (even some approximation of) the algorithm behind Matlab's areaint function.
There several ways to do this.
1) Integrate the contributions from latitudinal strips. Here the area of each strip will be (Rcos(A)(B1-B0))(RdA), where A is the latitude, B1 and B0 are the starting and ending longitudes, and all angles are in radians.
2) Break the surface into spherical triangles, and calculate the area using Girard's Theorem, and add these up.
3) As suggested here by James Schek, in GIS work they use an area preserving projection onto a flat space and calculate the area in there.
From the description of your data, in sounds like the first method might be the easiest. (Of course, there may be other easier methods I don't know of.)
Edit – comparing these two methods:
On first inspection, it may seem that the spherical triangle approach is easiest, but, in general, this is not the case. The problem is that one not only needs to break the region up into triangles, but into spherical triangles, that is, triangles whose sides are great circle arcs. For example, latitudinal boundaries don't qualify, so these boundaries need to be broken up into edges that better approximate great circle arcs. And this becomes more difficult to do for arbitrary edges where the great circles require specific combinations of spherical angles. Consider, for example, how one would break up a middle band around a sphere, say all the area between lat 0 and 45deg into spherical triangles.
In the end, if one is to do this properly with similar errors for each method, method 2 will give fewer triangles, but they will be harder to determine. Method 1 gives more strips, but they are trivial to determine. Therefore, I suggest method 1 as the better approach.
I rewrote the MATLAB's "areaint" function in java, which has exactly the same result.
"areaint" calculates the "suface per unit", so I multiplied the answer by Earth's Surface Area (5.10072e14 sq m).
private double area(ArrayList<Double> lats,ArrayList<Double> lons)
{
double sum=0;
double prevcolat=0;
double prevaz=0;
double colat0=0;
double az0=0;
for (int i=0;i<lats.size();i++)
{
double colat=2*Math.atan2(Math.sqrt(Math.pow(Math.sin(lats.get(i)*Math.PI/180/2), 2)+ Math.cos(lats.get(i)*Math.PI/180)*Math.pow(Math.sin(lons.get(i)*Math.PI/180/2), 2)),Math.sqrt(1- Math.pow(Math.sin(lats.get(i)*Math.PI/180/2), 2)- Math.cos(lats.get(i)*Math.PI/180)*Math.pow(Math.sin(lons.get(i)*Math.PI/180/2), 2)));
double az=0;
if (lats.get(i)>=90)
{
az=0;
}
else if (lats.get(i)<=-90)
{
az=Math.PI;
}
else
{
az=Math.atan2(Math.cos(lats.get(i)*Math.PI/180) * Math.sin(lons.get(i)*Math.PI/180),Math.sin(lats.get(i)*Math.PI/180))% (2*Math.PI);
}
if(i==0)
{
colat0=colat;
az0=az;
}
if(i>0 && i<lats.size())
{
sum=sum+(1-Math.cos(prevcolat + (colat-prevcolat)/2))*Math.PI*((Math.abs(az-prevaz)/Math.PI)-2*Math.ceil(((Math.abs(az-prevaz)/Math.PI)-1)/2))* Math.signum(az-prevaz);
}
prevcolat=colat;
prevaz=az;
}
sum=sum+(1-Math.cos(prevcolat + (colat0-prevcolat)/2))*(az0-prevaz);
return 5.10072E14* Math.min(Math.abs(sum)/4/Math.PI,1-Math.abs(sum)/4/Math.PI);
}
You mention "geography" in one of your tags so I can only assume you are after the area of a polygon on the surface of a geoid. Normally, this is done using a projected coordinate system rather than a geographic coordinate system (i.e. lon/lat). If you were to do it in lon/lat, then I would assume the unit-of-measure returned would be percent of sphere surface.
If you want to do this with a more "GIS" flavor, then you need to select an unit-of-measure for your area and find an appropriate projection that preserves area (not all do). Since you are talking about calculating an arbitrary polygon, I would use something like a Lambert Azimuthal Equal Area projection. Set the origin/center of the projection to be the center of your polygon, project the polygon to the new coordinate system, then calculate the area using standard planar techniques.
If you needed to do many polygons in a geographic area, there are likely other projections that will work (or will be close enough). UTM, for example, is an excellent approximation if all of your polygons are clustered around a single meridian.
I am not sure if any of this has anything to do with how Matlab's areaint function works.
I don't know anything about Matlab's function, but here we go. Consider splitting your spherical polygon into spherical triangles, say by drawing diagonals from a vertex. The surface area of a spherical triangle is given by
R^2 * ( A + B + C - \pi)
where R is the radius of the sphere, and A, B, and C are the interior angles of the triangle (in radians). The quantity in the parentheses is known as the "spherical excess".
Your n-sided polygon will be split into n-2 triangles. Summing over all the triangles, extracting the common factor of R^2, and bringing all of the \pi together, the area of your polygon is
R^2 * ( S - (n-2)\pi )
where S is the angle sum of your polygon. The quantity in parentheses is again the spherical excess of the polygon.
[edit] This is true whether or not the polygon is convex. All that matters is that it can be dissected into triangles.
You can determine the angles from a bit of vector math. Suppose you have three vertices A,B,C and are interested in the angle at B. We must therefore find two tangent vectors (their magnitudes are irrelevant) to the sphere from point B along the great circle segments (the polygon edges). Let's work it out for BA. The great circle lies in the plane defined by OA and OB, where O is the center of the sphere, so it should be perpendicular to the normal vector OA x OB. It should also be perpendicular to OB since it's tangent there. Such a vector is therefore given by OB x (OA x OB). You can use the right-hand rule to verify that this is in the appropriate direction. Note also that this simplifies to OA * (OB.OB) - OB * (OB.OA) = OA * |OB| - OB * (OB.OA).
You can then use the good ol' dot product to find the angle between sides: BA'.BC' = |BA'|*|BC'|*cos(B), where BA' and BC' are the tangent vectors from B along sides to A and C.
[edited to be clear that these are tangent vectors, not literal between the points]
Here is a Python 3 implementation, loosely inspired by the above answers:
def polygon_area(lats, lons, algorithm = 0, radius = 6378137):
"""
Computes area of spherical polygon, assuming spherical Earth.
Returns result in ratio of the sphere's area if the radius is specified.
Otherwise, in the units of provided radius.
lats and lons are in degrees.
"""
from numpy import arctan2, cos, sin, sqrt, pi, power, append, diff, deg2rad
lats = np.deg2rad(lats)
lons = np.deg2rad(lons)
# Line integral based on Green's Theorem, assumes spherical Earth
#close polygon
if lats[0]!=lats[-1]:
lats = append(lats, lats[0])
lons = append(lons, lons[0])
#colatitudes relative to (0,0)
a = sin(lats/2)**2 + cos(lats)* sin(lons/2)**2
colat = 2*arctan2( sqrt(a), sqrt(1-a) )
#azimuths relative to (0,0)
az = arctan2(cos(lats) * sin(lons), sin(lats)) % (2*pi)
# Calculate diffs
# daz = diff(az) % (2*pi)
daz = diff(az)
daz = (daz + pi) % (2 * pi) - pi
deltas=diff(colat)/2
colat=colat[0:-1]+deltas
# Perform integral
integrands = (1-cos(colat)) * daz
# Integrate
area = abs(sum(integrands))/(4*pi)
area = min(area,1-area)
if radius is not None: #return in units of radius
return area * 4*pi*radius**2
else: #return in ratio of sphere total area
return area
Please find a somewhat more explicit version (and with many more references and TODOs...) here.
You could also have a look at this code of the spherical_geometry package: Here and here. It does provide two different methods for calculating the area of a spherical polygon.