This is a linear algebra question which i am expected to understand before i can start tackling 2D and 3D programming. I am a business application programmer but i am exploring an interest in game programming. I realise that this maybe a simple question to some, so please bear with me.
The line L passes through the points P1 (3, -1, 2) and P2 (1, -2, -1). Determine the point of intersection of L in the xy- plane.
Okay using those two points you can find the equation of a line (google finding the equation of a line in 3d) from that point on you can equate the equation of a line and the equation of the xy-plane to figure out their intersection (google finding intersection of two planes in 3D).
You can use the z-coordinate of the line as the independent variable, and use the two points to get the formula for the x- and y- coordinates in terms of z.
First, we define the slopes:
x_slope=(x2-x1)/(z2-z1);
y_slope=(y2-y1)/(z2-z1);
Then we have that:
x-x1=x_slope*(z-z1)
and
y-y1=y_slope*(z-z1)
Setting z to 0 and solving for x and y, we get
x_plane_coord=x1-(x_slope*z1);
y_plane_coord=y1-(y_slope*z1);
Related
So the first problem will be explaining what I am after clearly.
I have two non-rational 3D b-splines. The first b-spline it the guiding spline. The second b-spline is a reference and it is essentially 'inside' of the first spline. ( the splines were generated in Solidworks )
Imagine a circular playground slide. The first spline is the center line of the slide. The second spline is the inside edge of the slide.
The inside spline will tend to be shorter than the center spline. The inside will also tend to have more curvature at any given point than the center.
The path of the slide is not perfectly circular. But the inside spline is always 'parallel' to the outside. ( very liberal use of the word parallel here )
What I am after:
Given a point along the center curve, I would like to find the point on the inside curve that is on the plane that is defined by the normal to the tangent of the center spline at that point.
Where I am at:
I am using the geomdl library in python to manipulate the splines.
I can choose a distance along the center spline and from geomdl I get the 3D point and the tangent vector (A,B,C) of that point and therefore the plane at that point that is normal to the spline at that point.
What I am doing:
From the tangent vector and the point I compute the equation of the plane in the form of:
Ax + By + Cz = D.
From there I guess at the point at the same distance on the inside spline and plug it into the equation for the plane that I already have. I use the error in D to guess at which way I should bump my guess on where the point on the inside curve might really be.
[ I understand that over the entire length of the two splines there may be more than one solution. i.e. if the curve wraps more than 180° there would be more than one point on the inside curve that lands on the plane defined by the center curve. In the local area that i am interested in this will not be a problem. Any second point would also be a long ways away from the center line. i.e. the correct point will be no more than 25 mm from the center point. A non-local point will be at least 3000 mm away. ]
This mostly works. But from time to time it fails. i.e. if D is very near 0 my guesses will diverge from the answer.
Currently I make 10 guesses, each guess having a smaller delta guess than the last.
I have a great number of these points to evaluate. My solution requires 10 X the number of calculations so it is not terribly efficient.
From my Google searches I believe that using the error in D in the equation of a plane may not be correct. I 'think' that D is the distance of the plane to the origin.(yes /no?) Therefore I am really comparing the distance of the two planes from the origin and not really from each other. If my guess happens to be on the "other side" of the origin then the distance's may be the same but opposite.
My Question:
What is the correct way to go about this?
Is my assumption that D is the distance from the plane to the origin?
Is driving the error in D between the two points valid?
What is the correct way to do this?
Restate my question in different terms
Given a plane (Ax + By + Cz = D) how do I find the point on a given b-spline that pierces ( or is coincident to ) that plane (using geomdl.bcurve)?
( I am very much in over my head here so please forgive if this does not make sense )
Say I want to construct a 3D cubic Bézier curve, and I already have both end-points, and the direction (normal vector) for both control points. How can I choose the distance of both control points to their respective end-points in order to make the curve as 'nicely rounded' as possible?
To formalize 'nicely rounded': I think that means maximizing the smallest angle between any two segments in the curve. For example, having end-points (10, 0, 0) and (0, 10, 0) with respective normal vectors (0, 1, 0) and (1, 0, 0) should result in a 90° circular arc. For the specific case of 2D circular arcs, I've found articles like this one. But I haven't been able to find anything for my more general case.
(Note that these images are just to illustrate the 'roundness' concept. My curves are not guaranteed to be plane-aligned. I may replace the images later to better illustrate that point.)
This is a question of aesthetics, and if the real solution is unknown or too complicated, I would be happy with a reasonable approximation. My current approximation is too simplistic: choosing half the distance between the two end-points for both control point distances. Someone more familiar with the math will probably be able to come up with something better.
(PS: This is for open-source software, and I would be happy to give credit on GitHub.)
Edit: Here are some other images to illustrate a 3D case (jsfiddle):
Edit 2: Here's a screenshot of an unstable version of ApiNATOMY to give you an idea of what I'm trying to do. I'm creating 3D tubes to represent blood-vessels, connecting different parts of an anatomical schematic:
(They won't let me put in a jsfiddle link if I don't include code...)
What you are basically asking is to have curvature over the spline as constant as possible.
A curve with constant curvature is just a circular arc, so it makes sense to try to fit such an arc to your input parameters. In 2D, this is easy: construct the line which goes through your starting point and is orthogonal to the desired direction vector. Do the same for the ending point. Now intersect these two lines: the result is the center of the circle which passes through the two points with the desired direction vectors.
In your example, this intersection point would just be (0,0), and the desired circular arc lies on the unit circle.
So this gives you a circular arc, which you can either use directly or use the approximation algorithm which you have already cited.
This breaks down when the two direction vectors are collinear, so you'd have to fudge it a bit if this ever comes up. If they point at each other, you can simply use a straight line.
In 3D, the same construction gives you two planes passing through the end points. Intersect these, and you get a line; on this line, choose the point which minimizes the sum of squared distances to the two points. This gives you the center of a sphere which touches both end points, and now you can simply work in the plane spanned by these three points and proceed as in 2D.
For the special case where your two end points and the two known normal vector for the control points happen to make the Bezier curve a planar one, then basically you are looking for a cubic Bezier curve that can well approximate a circular arc. For this special case, you can set the distance (denoted as L) between the control point and their respective end point as L = (4/3)*tan(A/4) where A is the angle of the circular arc.
For the general 3D case, perhaps you can apply the same formula as:
compute the angle between the two normal vectors.
use L=(4/3)*tan(A/4) to decide the location of your control points.
if your normals are aligned in a plane
What you're basically doing here is creating an elliptical arc, in 3D, where the "it's in 3D" part is completely irrelevant, since it's just a 2D curve, rotated/translated to sit in your 3D space. So let's just solve the 2D case, and then the RT is entirely up to you.
Creating the "perfect" cubic Bezier between two points on an arc comes with limitations. You basically can't create good looking arcs that span more than a quarter circle. So, with that said: your start and end point normals give you a 2D angle between your normal vectors, which is the same angle as between your start and end tangents (since normals are perpendicular to tangents). So, let's:
align our curve so that the tangent at the start is 0
plug the angle between tangents into the formula given in the section on Circle approximation in the Primer on Bezier curves. This is basically just dumb "implementing the formula for c1x/c1y/c2x/c2y as a function that takes an angle as argument, and spits out four values as c1(x,y) and c2(x,y) coordinats".
There is no step 3, we're done.
After step 2, you have your control points in 2D to create the most circular arc between a start and end point. Now you just need to scale/rotate/translate it in 3D so that it lines up with where you needed your start and end point to begin with.
if your normals are not aligned in a plane
Now we have a problem, although one that we can deal with by treating the dimensions as separate things entirely. Instead of creating a single 2D curve, we're going to create three: one that's the X/Y projection, one that's the X/Z projection, and one that's the Y/Z projection. For all three of these, we're going to abstract the control points in exactly the same way as before, and then we simply take the projective control points (three for each control point), and then go "okay, we now have X, Y, and Z projective coordinates. That means we have (X,Y,Z) coordinates", and done again.
Based on the following resources, I have been trying to get resolution independent cubic bezier rendering on the GPU to work:
GPU Gems 3 Chapter 25
Curvy Blues
Resolution Independent Curve Rendering using Programmable Graphics Hardware
But as stated in the Curvy Blues website, there are errors in the documents on the other two websites. Curvy Blues tells me to look at the comments, but I don't seem to be able to find those comments. Another forum somewhere tells me the same, I don't remember what that forum was. But there is definitely something I am missing.
Anyway, I have tried to regenerate what is happening and I fail to understand the part where the discriminant is calculated from the determinants of a combination of transformed coordinates.
So I have the original coordinates, I stick them in a 4x4 matrix, transform this matrix with the M3-matrix and get the C-matrix.
Then I create 3x3 matrices from the coordinates in the C-matrix and calculate the determinants, which then can be combined to create the a, b and c of the quadratic equation that will help me find the roots.
Problem is, when I do it exactly like that: the discriminant is incorrect. I clearly put in coordinates for a serpentine (a symmetric one, but a correct serpentine), but it states it is a cusp.
When I calculate it myself using wxMaxima, deriving to 1st and 2nd order and then calculating the cross-product, simplifying to a quadratic equation, the discriminant of that equation seems to be correct when I put in the same coordinates.
When I force the code to use my own discriminant to determine if it's a serpentine or not, but I use the determinants to calculate the further k,l,m texture coordinates, the result is also incorrect.
So I presume there must be an error in the determinants.
Can anyone help me get this right?
I think I have managed to solve it. The results are near to perfect (sometimes inverted, but that's probably a different problem).
This is where I went wrong, and I hope I can help other people to not waste all the time I have wasted searching this.
I have based my code on the blinn-phong document.
I had coordinates b0, b1, b2, b3. I used to view them as 2D coordinates with a w, but I have changed this view, and this solved the problem. By viewing them as 3D coordinates with z = 0, and making them homogenous 4D coordinates for transformation (w = 1), the solution arrived.
By calculating the C matrix: C = M3 * B, I got these new coordinates.
When calculating the determinants d0, d1, d2, d3, I used to take the x, y coordinates from columns 0 and 1 in the C matrix, and the w factor from column 2. WRONG! When you think of it, the coordinates are actually 3D coordinates, so, for the w-factors, one should take column 3 and ignore column 2.
This gave me correct determinants, resulting in a discriminant that was able to sort out what type of curve I was handling.
But beware, what made my search even longer was the fact that I assumed that when it is visibly a serpentine, the result of the discriminant should always be > 0 (serpentine).
But this is not always the case, when you have a mathematically perfect sepentine (coordinates are so that the mean is exact middle), the determinant will say it's a cusp (determinant = 0). I used to think that this result was wrong, but it isn't. So don't be fooled by this.
The book GPU Gem 3 has a mistake here, and the page on nVidia's website has the mistake too:
a3 = b2 * (b1 x b1)
It's actually a3 = b2 * (b1 x b0).
There're other problems about this algorithm: the exp part of the floating point will overflow during the calculation, so you should be cautious and add normalize operations into your code.
Basically, I have a set of up to 100 co-ordinates, along with the desired tangents to the curve at the first and last point.
I have looked into various methods of curve-fitting, by which I mean an algorithm with takes the inputted data points and tangents, and outputs the equation of the cure, such as the gaussian method and interpolation, but I really struggled understanding them.
I am not asking for code (If you choose to give it, thats acceptable though :) ), I am simply looking for help into this algorithm. It will eventually be converted to Objective-C for an iPhone app, if that changes anything..
EDIT:
I know the order of all of the points. They are not too close together, so passing through all points is necessary - aka interpolation (unless anyone can suggest something else). And as far as I know, an algebraic curve is what I'm looking for. This is all being done on a 2D plane by the way
I'd recommend to consider cubic splines. There is some explanation and code to calculate them in plain C in Numerical Recipes book (chapter 3.3)
Most interpolation methods originally work with functions: given a set of x and y values, they compute a function which computes a y value for every x value, meeting the specified constraints. As a function can only ever compute a single y value for every x value, such an curve cannot loop back on itself.
To turn this into a real 2D setup, you want two functions which compute x resp. y values based on some parameter that is conventionally called t. So the first step is computing t values for your input data. You can usually get a good approximation by summing over euclidean distances: think about a polyline connecting all your points with straight segments. Then the parameter would be the distance along this line for every input pair.
So now you have two interpolation problem: one to compute x from t and the other y from t. You can formulate this as a spline interpolation, e.g. using cubic splines. That gives you a large system of linear equations which you can solve iteratively up to the desired precision.
The result of a spline interpolation will be a piecewise description of a suitable curve. If you wanted a single equation, then a lagrange interpolation would fit that bill, but the result might have odd twists and turns for many sets of input data.
I'm trying to find a way to calculate the intersection between a b-spline and a straight line. So far Google hasn't been much help.
A pure mathematical approach:
Transform the spline and the line so that the line lies on the X axis.
Calculate the points on the spline where Y = 0 (depends on the order of the spline).
Transform these points back to your original cordinate system.
If this is the way you are going I can work out the necessary formulas.
The most efficient algorithm that I've heard of is called Bezier clipping.
Here's a book chapter on curve and spline intersection (pdf).
Your best approach might be to break down your spline into individual line segments and test each line segment for intersection with the line. The spline may intersect the line in more than one point, so you'll also have to decide which one you're interested in.