Computing points within an angular distance in spherical coordinates - algorithm

Suppose I have a graticule (say 1 degree resolution) in spherical coordinates.
Now, assuming that a certain spherical object is in a known direction (known phi and lambda) and has a known angular diameter as viewed from the origin of the coordinate system, how can I efficiently compute a list of graticule points that "end up" on the object?
The naive algorithm is of course to calculate the angle between every graticule direction and the known (phi/lambda) direction of the object, and include the point if it is less than the angular radius. This is very slow if the graticule is fine.
What algorithms can I use to speed up this computation?

Let's you have base coordinates (lat0, lon0), grid step da and max big circle arc angle AA (half of your "known angular diameter").
You can use algorithm similar to rasterization at Cartesian plane: enumeration of integer points on every scanline (here parallels) inside a circle.
Start from the central (lat0, lon0) point. Walk along meridian up and down and get points at the parallel inside given angular radius
Edit: big circle arc calculation has been rewritten
For every point at meridian (lat[i], lon0) get list of points with the same latitude usinf BigArc calculation from here (distance section).
var a = Math.sin(diflat/2) * Math.sin(diflat/2) +
Math.cos(lat0) * Math.cos(alat) *
Math.sin(diflon/2) * Math.sin(diflon/2);
var BigArc = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
(This method might fail when pole lies inside radius)
meridiansteps = Floor(AA / da)
for i = - meridiansteps to meridiansteps:
diflat = da * i
alat = lat0 + diflat
addpoint(alat, lon0)
diflon = da
while BigArc <= AA:
addpoint(alat, lon0 + diflon)
addpoint(alat, lon0 - diflon) //symmetric
diflon = diflon + da

If you can find the closest point on the graticule to the object, for instance by projecting the direction to the object onto the orientation of the graticule, then you have one point which is either on the graticule or not, and if it is not on the graticule, no point is.
Because the object is convex, its projection onto the graticule should be convex, so the points on the graticule which end up on the object should be contiguous. With one point on the object, you can use binary chop to find the two points on either side of it which are only just on the object.
The set of graticule points on the object is then all graticule points between these two furthest points.

Related

How to Follow the Path of a Super Ellipse with 2 Linked Axis

I have two axis linked together ; Axis A, and Axis B. Axis B is attached to the end of Axis A and so its point of origin can vary with the angle of Axis A . Attached to Axis B is a Circle whose Diameter is 10 (and can become smaller). I need to move the edge point of the circle to intersect a Super-Ellipse at each of 38 Cartesian points x,y. So the end point of my axis B - center of the circle should follow the same basic path as the 38 points of the super ellipse - radius of circle. Once I have these points - I will need to determine the position of Axis A x_2,y_2 and angle (or more appropriately just the distance from 0 degree angle to reach the required angle to position x_2,y_2. I then need to position Axis B with relation to Axis A in order to have Axis B X_3,Y_3 match the following of the Super-Ellipse where the center of the circle is supposed to be.
I have a drawing attached and a plot in Excel where I am off as you can see the bow tie is not what I should have. I have also included the points to the super ellipse along with some quick points on the graph. I am not a math major - I am willing to learn if you post the name of an equation - so far I have learned about carnot, parametric equation for circles and formulas for parabolas - but I am still having trouble.
Axis A Radius 13" image is 90 degree rotation
X_Sub1 , Y_Sub1
-6.5 , 5
Axis B Radius 9" image is 180 degree rotation
X_Sub2 , Y_Sub2
6.5 , 5
Circle Diameter 10"
Circle Radius 5"
Super Ellipse
# 12"width
# 8.75" Deep Vertex -8.75
Points Along the Super Ellipse.
0.0000, 0.0000
0.2188, -0.6250
0.2188, -1.2500
0.2433, -1.8750
0.3290, -2.5000
0.4753, -3.1073
0.6804, -3.7091
0.9424, -4.2990
1.2585, -4.8712
1.6255, -5.4197
2.0397, -5.9388
2.4967, -6.4233
2.9920, -6.8682
3.5203, -7.2889
4.0764, -7.7213
4.6544, -8.0500
5.2285, -8.3553
5.7525, -8.5000
6.2188, -8.5516
6.6851, -8.5000
7.1891, -8.3553
7.7832, -8.0500
8.3612, -7.7213
8.9173, -7.2889
9.4456, -6.8682
9.9409, -6.4233
10.3979,-5.9388
10.8121,-5.4197
11.1791,-4.8712
11.4952,-4.2990
11.7572,-3.7091
11.9623,-3.1073
12.1086,-2.5000
12.1943,-1.8750
12.2188,-1.2500
12.2188,-0.6250
12.4376, 0.0000
First, suppose we have 3 points along the super-ellipse, p0 = (2.4967, -6.4233), p1 = (2.9920, -6.8682), and p2 = (3.5203, -7.2889). Let's figure out how to position it to touch the point p1.
First of all at the point p1 the tangent line should be very close to parallel to the line from p0 to p2. So it should be parallel to p2 - p0 = (3.5203, -7.2889) - (2.4967, -6.4233) = (1.0236, -0.8656). But you want the disk to be perpendicular to this. We can construct a perpendicular to the vector (x, y) by (-y, x), which gives us (0.8656, 1.0236) as a direction. (There are two perpendiculars, looking at the diagram this is obviously the correct one.) This means that we want to put the end of axis B a distance of 5 in that direction. Which means it needs to be a distance of 5 in the direction (0.8656, 1.0236) from p1 = (2.9920, -6.8682). So it should be at the position (2.9920, -6.8682) + 5 * (0.8656, 1.0236) / sqrt(0.8656^2 + 1.0236^2) = (6.22057, -3.050307).
Now that we know where the end of axis B is, assuming we know where the start of axis A is (you didn't specify that), we can use the law of cosines (see http://mathworld.wolfram.com/LawofCosines.html) to figure out the cos of the angles that you want. Now you can use the arccosine function to figure out the angles in question.
This procedure can be followed for every point. Figure out what you think it should be tangent to, find the orthogonal, find where you want the end of B to be, then you have a triangle that you can use the cosine law on.

How to check a point is inside an ellipsoid with orientation?

For an ellipsoid of the form
with orientation vector and centre at point , how to find whether a point is inside the ellipsoid or not?
An additional note that the geometry actually is with a=b (spheroid) and therefore one axis is sufficient to define orientation
Note: I see a similar question asked in the forum. But, it is about an ellipsoid at origin and without any arbitrary orientation and here both arbitrary position and orientation are considered.
Find affine transform M that translates this ellipse in axis-oriented one (translation by -p and rotation to align orientation vector r and proper coordinate axis).
Then apply this transform to point p and check that p' lies inside axis-oriented ellipsoid, i.e.
x^2/a^2+ y^2/b^2+z^2/c^2 <= 1
Create a coordinate system E with the center at p and with the long axis of the ellipse aligned with r. Create a matrix that can transform global coordinates to the coordinate system E. Then put the transformed coordinates into the ellipse equation.
A center point p and an "orientation vector" r do not suffice to completely specify the position of the ellipsoid, there is one degree of freedom left. Your problem is indeterminate.
If your vector r is a unit vector from the origin to the pole, then the test for whether a point q is in (or on) the ellipse is:
v = q-p; // 3d vector difference
dot = v.r; // 3d dot product
f = dot*dot;
g = v.v - f; // 3d dot product and scalar subtraction
return f/(b*b) + g/(a*a) <= 1
Note that if the ellipse was aligned so that r was the z unit vector, then the test above translates into the usual test for inclusion of a point in an ellipse.

Clip d3 voronoi with d3 hull

I would like to draw a d3 voronoi diagram and clip it like d3 hull borders do bound a collection of nodes or any similar clipping.
The red line in this Screenshot shows what i would like to achieve.
How can it be done ?
The d3.geom.hull function will find a polygon that contains all your nodes tightly, with no extra spacing. That of course would cancel out much of the purpose of the Voronoi regions, which are intended to add some active space around the nodes. So what you need to calculate is a polygon that is a certain padding distance larger than the convex hull polygon on all sides.
My recommended algorithm:
Use d3.geom.hull(nodes) to calculate the array of vertices that define the tight boundary of your nodes.
Use those vertices to create a d3 polygon object.
Calculate the center of that polygon with .centroid().
For each vertex in your convex hull, calculate a point that is padding distance farther away from the center of the polygon.
Use this expanded polygon to clip all the polygons in the array returned by Voronoi function.
Sample code:
var hullFunction = d3.geom.hull()
.x(/*x accessor function*/)
.y(/*y accessor function*/);
var tightHull = hullFunction(nodes); //returns an array of vertices
var centerPoint = d3.geom.polygon(tightHullArray).centroid();
var expandedHull = tightHullArray.map( function(vertex) {
//Create a new array of vertices, each of which is the result
//of running this function on the corresponding vertex of the
//original hull.
//Each vertex is of the form [x,y]
var vector = [vertex[0] - centerPoint[0],
vertex[1] - centerPoint[1] ];
//the vector representing the line from center to this point
var vectorLength = Math.sqrt(vector[0]*vector[0]
+ vector[1]*vector[1]);
//Pythagorus' theorem to get the length of the line
var normalizedVector = [vector[0] / vectorLength,
vector[1] / vectorLength];
//the vector scaled down to length 1, but with the same angle
//as the original vector
return [vertex[0] + normalizedVector[0]*padding,
vertex[1] + normalizedVector[1]*padding ];
//use the normalized vector to adjust the vertex point away from
//the center point by a distance of `padding`
});
var clippedVoronoi = voronoiPolygons.map(function(voronoi) {
//voronoiPolygons would be the array returned by the voronoi function
return expandedHull.clip(voronoi);
//I think this is correct; if you get weird results, try
// return voronoi.clip(expandedHull);
});
I recently made an example to illustrate to myself how polygon clipping works:
http://tributary.io/inlet/8263747
You can see the clipping code in the update function, and the rendering code in the process function. drag the points around to see how the clipping will be affected.
A couple things to watch out for:
the order of the points in the "hull" (or clipping path in my example) matters. Your polygon has to be counter-clockwise as well as convex (no caves). If these conditions aren't met there is no error, you just get back an empty array.
the polygon operations manipulate your point arrays in place, if you don't want your geometry itself clipped, but want a copy you need to make a copy first.

Scaling vectors from a center point?

I'm trying to figure out if I have points that make for example a square:
* *
* *
and let's say I know the center of this square.
I want a formula that will make it for eample twice its size but from the center
* *
* *
* *
* *
Therefore the new shape is twice as large and from the center of the polygon. It has to work for any shape not just squares.
I'm looking more for the theory behind it more than the implementation.
If you know the center point cp and a point v in the polygon you would like to scale by scale, then:
v2 = v - cp; // get a vector to v relative to the centerpoint
v2_scaled = v2 * scale; // scale the cp-relative-vector
v1_scaled = v2_scaled + cp; // translate the scaled vector back
This translate-scale-translate pattern can be performed on vectors of any dimension.
If you want the shape twice as large, scale the distance of the coordinates to be sqrt(2) times further from the center.
In other words, let's say your point is at (x, y) and the center is (xcent, ycent). Your new point should be at
(xcent + sqrt(2)*(x - xcent), ycent + sqrt(2)*(y - ycent))
This will scale the distances from the new 'origin', (xcent, ycent) in such a way that the area doubles. (Because sqrt(2)*sqrt(2) == 2).
I'm not sure there's a clean way to do this for all types of objects. For relatively simple ones, you should be able to find the "center" as the average of all the X and Y values of the individual points. To double the size, you find the length and angle of a vector from the center to the point. Double the length of the vector, and retain the same angle to get the new point.
Edit: of course, "twice the size" is open to several interpretations (e.g., doubling the perimeter vs. doubling the area) These would change the multiplier used above, but the basic algorithm would remain essentially the same.
To do what you want you need to perform three operations: translate the square so that its centroid coincides with the origin of the coordinate system, scale the resulting square, translate it back.

Calculating the Bounding Rectangle at an Angle of a Polygon

I have the need to determine the bounding rectangle for a polygon at an arbitrary angle. This picture illustrates what I need to do:
alt text http://kevlar.net/RotatedBoundingRectangle.png
The pink rectangle is what I need to determine at various angles for simple 2d polygons.
Any solutions are much appreciated!
Edit:
Thanks for the answers, I got it working once I got the center points correct. You guys are awesome!
To get a bounding box with a certain angle, rotate the polygon the other way round by that angle. Then you can use the min/max x/y coordinates to get a simple bounding box and rotate that by the angle to get your final result.
From your comment it seems you have problems with getting the center point of the polygon. The center of a polygon should be the average of the coordinate sums of each point. So for points P1,...,PN, calculate:
xsum = p1.x + ... + pn.x;
ysum = p1.y + ... + pn.y;
xcenter = xsum / n;
ycenter = ysum / n;
To make this complete, I also add some formulas for the rotation involved. To rotate a point (x,y) around a center point (cx, cy), do the following:
// Translate center to (0,0)
xt = x - cx;
yt = y - cy;
// Rotate by angle alpha (make sure to convert alpha to radians if needed)
xr = xt * cos(alpha) - yt * sin(alpha);
yr = xt * sin(alpha) + yt * cos(alpha);
// Translate back to (cx, cy)
result.x = xr + cx;
result.y = yr + cx;
To get the smallest rectangle you should get the right angle. This can acomplished by an algorithm used in collision detection: oriented bounding boxes.
The basic steps:
Get all vertices cordinates
Build a covariance matrix
Find the eigenvalues
Project all the vertices in the eigenvalue space
Find max and min in every eigenvalue space.
For more information just google OBB "colision detection"
Ps: If you just project all vertices and find maximum and minimum you're making AABB (axis aligned bounding box). Its easier and requires less computational effort, but doesn't guarantee the minimum box.
I'm interpreting your question to mean "For a given 2D polygon, how do you calculate the position of a bounding rectangle for which the angle of orientation is predetermined?"
And I would do it by rotating the polygon against the angle of orientation, then use a simple search for its maximum and minimum points in the two cardinal directions using whatever search algorithm is appropriate for the structure the points of the polygon are stored in. (Simply put, you need to find the highest and lowest X values, and highest and lowest Y values.)
Then the minima and maxima define your rectangle.
You can do the same thing without rotating the polygon first, but your search for minimum and maximum points has to be more sophisticated.
To get a rectangle with minimal area enclosing a polygon, you can use a rotating calipers algorithm.
The key insight is that (unlike in your sample image, so I assume you don't actually require minimal area?), any such minimal rectangle is collinear with at least one edge of (the convex hull of) the polygon.
Here is a python implementation for the answer by #schnaader.
Given a pointset with coordinates x and y and the degree of the rectangle to bound those points, the function returns a point set with the four corners (and a repetition of the first corner).
def BoundingRectangleAnglePoints(x,y, alphadeg):
#convert to radians and reverse direction
alpha = np.radians(alphadeg)
#calculate center
cx = np.mean(x)
cy = np.mean(y)
#Translate center to (0,0)
xt = x - cx
yt = y - cy
#Rotate by angle alpha (make sure to convert alpha to radians if needed)
xr = xt * np.cos(alpha) - yt * np.sin(alpha)
yr = xt * np.sin(alpha) + yt * np.cos(alpha)
#Find the min and max in rotated space
minx_r = np.min(xr)
miny_r = np.min(yr)
maxx_r = np.max(xr)
maxy_r = np.max(yr)
#Set up the minimum and maximum points of the bounding rectangle
xbound_r = np.asarray([minx_r, minx_r, maxx_r, maxx_r,minx_r])
ybound_r = np.asarray([miny_r, maxy_r, maxy_r, miny_r,miny_r])
#Rotate and Translate back to (cx, cy)
xbound = (xbound_r * np.cos(-alpha) - ybound_r * np.sin(-alpha))+cx
ybound = (xbound_r * np.sin(-alpha) + ybound_r * np.cos(-alpha))+cy
return xbound, ybound

Resources