Find the radius ( or curvature ) at a point on a bspline using geomdl / nurbs - bspline

I would like to find the curvature at a given point on a 3D b-spline.
I believe that I want to use the derivatives of the spline at that point to calculate the curvature at that point but I do not understand how.
I have defined a 3D bspline (taken from SolidWorks (where it came from is not relevant )) in geomdl. I can evaluate any point on the spline using Curve.evaluate_single(). This appears to work correctly. I have verified the returned points against the SolidWorks model so I assume I have implemented the bspline in nurbs correctly.
I need to find the radius at a various points along this curve. From my Google searching I think that I want to use Curve.derivatives() to calculate the instantaneous curvature at that point. But I do not understand how to get the results of Curve.derivatives() into a radius.
So below is the result of Curve.derivatives(SomePointOnPath,4):
[ [74.66019681782404, 131.77035668055586, 19.88498274391211],
[-2719.7097781710354, -598.8099790539873, -711.5032638750225],
[-5384.519486543373, 1273.8662545231637, 19431.220551950217],
[93757.48746982217, -22247.397114396095, 31343.52746776864],
[0.0, 0.0, 0.0]]
By taking points a small step either side of this point I have calculated the radius at this point to be about 409 ( Solving for radius of a circle given 3 points )
I do not understand what the results from Curve.derivatives() are telling me.
(the first tuple is the coordinates of the point, beyond that I am lost)
I expect the radius at this particular point to be about 409.
My fundamental question is two parts:
What are the results telling me. What do they mean.
How do I use these result to calculate the radius at this point.

The radius of curvature of a curve can be computed as |C'|^3/|C' X C"| where C' and C" are the first and the 2nd derivative vectors, X is the cross product operator and |.| is the vector's magnitude. So, you will need the first and the 2nd derivatives at that point to compute the radius of curvature.
Curve.derivatives(SomePointOnPath,4) returns the first 4 derivatives of the curve and the 0-th derivative is the position of the point on the curve. Therefore, the first derivative is [-2719.7097781710354, -598.8099790539873, -711.5032638750225] and the 2nd derivative is [-5384.519486543373, 1273.8662545231637, 19431.220551950217]. So, we can use these two vectors to do our computation and obtain a radius of curvature 408.9176414, which is close to your estimated value 409.
On a side note, you can simply pass '3' as the 2nd argument to Curve.derivatives() as the 3rd derivatvie vector has no use in the computation of radius of curvature.

Related

Calculating the normal of a point on a heightfield

I have a spherical heightfield, defined by a function f(x, y, z) which returns the distance from the origin of the surface of the heightfield of a line which passes from the origin through (x,y,z).
(In other words, the isosurface for my heightfield is |x,y,z| = f(x,y,z).)
(Also, for the sake of discussion below, I'm going to assume that surface(x,y,z) is the location of the point on the surface directly below (x,y,z).)
When rendering this, I need to calculate the normal for any point on the heightfield. What's the cheapest way of doing this?
To calculate the normal of a point on a rectangular heightfield, the usual trick is to offset (x,y,z) slightly in two directions parallel to the nominal surface, calculate three points on the heightfield to form a triangle, and then use the cross product to calculate the triangle's normal. This is easy as the three points can simply be surface(x,y,z), surface(x+1,y,z) and surface(x,y+1,z) (or similar). But for a spherical heightfield it's a little trickier because the normal can point in any direction. Simply displacing by x and y won't do because if two of my points fall on a radius, then surface() of them will return the same location and I won't get a triangle.
In the past what I've done is to use the vector <x,y,z> as a radius from the sphere's origin; then calculate a vector perpendicular to it; then rotate this vector around <x,y,z> to give me my three points. But this is fiddly and expensive and shouldn't be necessary. There must be a cheaper way. What is it?
Calculate the surface() points and, if they are close enough to cause problems, carry out the more expensive (but accurate) calculation; otherwise, use the cheap/easy calculation.

collision prediction using minkowski sum

I want to use the minkowski sum to predict the exact point of collision between two convex shapes. By my understanding the point where the velocity vector intersects with the minkowski sum is the amount I have to move my object along the vector so they just touch (I already know they will collide). Here's an example of what I mean (for simplicity reasons I just used rectangles):
I mean I could just calculate the intersection with every line of the convex hull and just use the closest but that seems horribly inefficient. My idea was to calculate the simplex closest to the vector but I have no idea how best to do it. I found a algorithm which calculates the smallest distance between to objects or to be more precise the smallest distance from the minkowski sum to the origin (http://www.codezealot.org/archives/153). One part of the algorithm tries to find the simplex closest to origin which is kinda what I want to do. I tried to change it to my needs but I wasn't successful. To me it sounds like there should be a very simple solution but I am not that good with vector math.
I hope I could make my problem clear since my english is not so good :D
You can transform the problem as follows:
1) rotate the plane so that the velocity vector becomes horizontal
2) consider the portions of the polygon outlines facing each other (these are two convex polylines); now you have to find the shortest horizontal distance between these two polylines
3) through every vertex of one of the polylines, draw an horizontal line; this will parition the plane into a set of horizontal slices
4) transform every slice using a shear transformation that brings the two vertices defining it onto the Y axis by horizontal moves; this transform preserves horizontal distances
5) while the first polyline is transformed into a straight line (the Y axis), the other polyline is transformed into another polyline; find the vertex(es) closest to the Y axis. This gives you the length of the collision vector.
As a by-product, step 2) will tell you if the polygons do collide, if the ranges of Y values overlap.

How to recognize ellipse/ellipsoid from random points? UN-weighted average?

Suppose we are getting random points in 2D (or 3D) which tend to be on ellipse (or ellipsoid). We can't guarantee points are uniformly distributed over ellipse (ellipsoid surface).
The task is to determine ellipse (ellipsoid) parameters, i.e. center location and semi-axes.
We can't take average, because it will be weighted. I mean if points will come preliminary from one side of ellipse, averaging will give wrong results.
So the question is how to UN-weight the average?
UPDATE
I think in the case of ellipse, the parameters can be determined by statistical quantities like moments. Can they?
Any ellipse can be fully defined using 5 points (see a detailed reasoning here). So, if you know that the points are error-free and on an ellipse you can take any 5 points of your set and get the ellipse parameters.
If the points can have an error component you can fit an ellipse on the data set using something like gradient descent. As an error function I'd use the sum of the squares of the distances between the data points and the ellipse. For example, for each data point you can take the line defined by it and the current ellipse center, intersect it with the ellipse and consider the distances from the point to the closest of the 2 intersection points.
Finally, here's a Matlab package that implements something along those lines. The function documentation is also very informative.
Any point on the ellipse will obey the equation
x^2 / a ^ 2 + y ^ 2 / b ^ 2 = 1
If you have two such points, it should be solvable using simultaneous equations method

How do I calculate the up vector in a flight simulator?

I am writing 3D app for OpenGL ES 2.0 where the user sets a path and flies over some terrain. It's basically a flight simulator on rails.
The path is defined by a series of points created from a spline. Every timeslice I advance the current position using interpolation i.e. I interpolate between p0 to p1, then when I reach p1 I interpolate between p1 and p2, then finally back from pN to p0.
I create a view matrix with something analogous to gluLookAt. The eye coord is the current position, the look at is the next position along the path and an up (0, 0, 1). So the camera looks towards where it is flying to next and Z points towards the sky.
But now I want to "bank" as I turn. i.e. the up vector is not necessarily directly straight up but a changes based on the rate of turn. I know my current direction and my last direction so I could increment or decrement the bank by some amount. The dot product would tell me the angle of turn, and the a cross product would tell me if its to the left or right. I could maintain a bank angle and keep it within the range -/+70 degrees, incrementing or decrementing appropriately.
I assume this is the correct approach but I could spend a long time implementing it to find out it isn't.
Am I on the right track and are there samples which demonstrate what I'm attempting to do?
Since you seem to have a nice smooth plane flying in normal conditions you don't need much... You are almost right in your approach and it will look totally natural. All you need is a cross product between 3 sequential points A, B, C: cross = cross(A-B, C-B). Now cross is the vector you need to turn the plane around the "forward" vector: Naturally the plane's up vector is (-gravitation) usually (0,0,1) and forward vector in point B is C-B (if no interpolation is needed) now "side" vector is side = normalized(cross(forward, up)) here is where you use the banking: side = side + cross*planeCorrectionParameter and then up = cross(normalized(side), normalized(forward)). "planeCorrectionParameter" is a parameter you should play with, in reality it would represent some combination of parameters such as dimensions of wings and hull, air density, gravity, speed, mass...
Note that some cross operations above might need swap in parameter order (cross(a,b) should be cross(b,a)) so play around a bit with that.
Your approach sounds correct but it will look unnatural. Take for example a path that looks like a sin function: The plane might be "going" to the left when it's actually going to the right.
I can mention two solutions to your problem. First, you can take the derivative of the spline. I'm assuming your spline is a f(t) function that returns a point (x, y, z). The derivative of a parametric curve is a vector that points to the rotation center: it'll point to the center of a circular path.
A couple of things to note with the above method: the derivative of a straight line is 0, and the vector will also be 0, so you have to fix the up vector manually. Also, you might want to fix this vector so it won't turn upside down.
That works and will look better than your method. But it will still look unnatural for some curves. The best method I can mention is quaternion interpolation, such as Slerp.
At each point of the curve, you also have a "right" vector: the vector that points to the right of the plane. From the curve and this vector, you can calculate the up vector at this point. Then, you use quaternion interpolation to interpolate the up vectors along the curve.
If position and rotation depends only on spline curvature the easiest way will be Numerical differentiation of 3D spline (you will have 2 derivatives one for vertical and one for horizontal components). Your UP and side will be normals to the tangent.

Finding closest pair of points on a sphere

I know how to implement n log n closest pair of points algorithm (Shamos and Hoey) for 2D cases (x and y). However for a problem where latitude and longitude are given this approach cannot be used. The distance between two points is calculated using the haversine formula.
I would like to know if there is some way to convert these latitudes and longitudes to their respective x and y coordinates and find the closest pair of points, or if there is another technique that can be used to do it.
I would translate them to three dimensional coordinates and then use the divide and conquer approach using a plane rather than a line. This will definitely work correctly. We can be assured of this because when only examining points on the sphere, the two closest points by arc distance (distance walking over the surface) will also be the two closest by 3-d Cartesian distance. This will have running time O(nlogn).
To translate to 3-d coordinates, the easiest way is to make (0,0,0) the center of the earth and then your coordinates are (cos(lat)*cos(lon),cos(lat)*sin(lan),sin(lat)). For those purposes I'm using a scale for which the radius of the Earth is 1 in order to simplify calculations. If you want distance in some other unit, just multiply all quantities by the radius of the Earth when measured in that unit.
I should note that all this assumes that the earth is a sphere. It's not exactly one and points may actually have altitude as well, so these answers won't really be completely exact, but they will be very close to correct in almost every case.

Resources