Nearest plane to non-coplanar points? - c#

I have a number of non-coplanar 3D points and I want to calculate the nearest plane to them (They will always form a rough plane but with some small level of variation). This can be done by solving simultaneous linear equations, one for each point, of the form:
"Ax + By + Cz + D = 0"
The problem I'm having at the moment is twofold.
Firstly since the points are 3D floats they can't be relied on to be precise due to rounding errors.
Secondly all of the methods to solving linear equations programatically that I have found thus far involve using NXN matrices which severely limits what I would be able to do given that I have 4 unknowns and any number of linear equations (due to the variation in the number of 3D points).
Does anyone have a decent way to either solve the simultaneous linear equations without these constraints or, alternatively, a better way to calculate the nearest plane to non-coplanar points? (The precision of the plane calculation is not too much of a concern)
Thanks! :)

If your points are all close to the plane, you have a choice between ordinary least squares (where you see Z as a function of two independent variables X and Y and you minimize the sum of squared vertical distances to the plane), or total least squares (all variables independent, minimize the sum of normal distances). The latter requires a 3x3 SVD. (See http://en.wikipedia.org/wiki/Total_least_squares, unfortunately not the easiest presentation.)
If some of the points are outliers, you will need to resort to robust fitting methods. One of them is RANSAC: choose three points are random, build their plane and compute the sum of distances of all points to the plane, as a measure of fitness. Keep the best result after N drawings.

There are numerical methods for linear regression, which calculates the nearest line y=mx+c to a set of points. Your solution will be similar, only it has one more dimension and is thus a "planar regression".
If you don't care the mathematical accuracy of the algorithm and just want to get a rough result, then perhaps you'd randomly 3 points to construct a plane vector, then adjust it incrementally as you go through the rest of the points. Just some thoughts...

Related

Stretch noise value meanwhile keep it in range (math issue!)

I implemented a simplex noise algorithm (by KdotJPG: OpenSimplex2S) which works fine, but I'd like to add a "function" which can increase/decrease the contrast of the noise. The noise method returns a value between -1 and 1 but the overall result is quite homogeneous. It is not bad at all, but I need to get a different outcome now.
So basically I should "pull" the value of the noise toward the range edges.. this will result more contrasting noise (more distance between the smaller and bigger values). Of course this change must be consistent and proportionally scaled between -1 and 1 (or 0-1) to get natural result.
Actually this is pure mathematical issue, but I'm not good in math at all! I'd like to make it more understandable to give this picture of two graphs:
So, on these graph the Y axis is the noise value (-1 is bottom and +1 it the top) and X axis is the time passed. The left graph shows the original result of the noise generator, and the right is the stretched version what I need to get. As you can see on the right graph everything the same but their values stretched/pulled toward the edge (toward the min, max limit) but still in range.
Is there any math formula or c# built in function to stretch the return value of the noise proportionally respect to the min, max values (-1/1 or 0/1)? If you need the code of the noise you can see it here OpenSimplex2S too, but this is irrelevant in my case, as I just wish to modify its return value. Thanks!

How do you calculate a rectangular wave from input values?

Here's a picture to make it a little easier:
The blue line represents some input values that resemble waves with variable amplitudes and lengths. The y axis represents the values, the x axis represents time. Please note that there is quite some jitter in the wave. However, every wave has a certain minimum and maximum length.
The green line shows how the input values should be transformed.
Please note: The above picture is just a hand drawn example to explain the task. In an ideal case, the position of the rising and falling edges of the rectangular (green) wave are close to the blue waves average value. The height/amplitude of the green wave segments should match the values of the blue wave.
How do you calculate the green line?
Do you know of any C# libraries or algorithms to do that? I guess this could be a rather common task for electrical engineers, so there are most likely some common approaches available. If so, how are hey called?
How would you approach this requirements?
Any advice that helps in getting started is welcome.
Take a base frequency (f) at an amplitude (a).
Then add ODD harmonics with the inverse amplitude ie f * a + f3 * a/3 + f5 * a/5 + f7 * a/7 ...
This will tend towards a square wave as you add harmonics.
BTW Try doing the same with even harminics, and with all the harmonics - Great fun!!!
Good luck
Tony

Check if the mouse is over a Bézier curve [duplicate]

This question already has answers here:
Closest point on a cubic Bezier curve?
(6 answers)
Closed 4 years ago.
My approach was to loop trough the curve and check the mouse distance to various points
But the points get closer together as the curve get steeper, and if the mouse distance threshold is too high it prioritizes the first point in the loop instead of the closet to the mouse.
is there a way to get uniform points in it? Or to check if the mouse is over the Bézier curve and get the position in the curve?
I do it like this:
subdivide you curve to few chunks
tne number of chunks depends on the order of curve. As I usually use cubics I empirically find out that ~8 chunks is enough (for my purposes).
compute the closest point to a chunk
So simply handle each chunk as line and compute closest point on the line to the mouse position (minimal perpendicular distance). By computing it for each chunk and remember the closest one.
Now after this we know which chunk contain the "closest" point so from the intersection between line and perpendicular line to it going through mouse position from previous step we should have a parameter u=<0,1> telling us where on the chunk line the closest point is and we also know the curve parameter t of both endpoints of the chunk line (t0,t1). From this we can approximate t for the closest point simply by doing this:
t = t0 + (t1-t0)*u
On the image t0=0.25 and t1=0.375. This is sometimes enough but if you want better solution so after this just set:
dt = (t1-t0)/4
t0 = t-dt
t1 = t+dt
Use the t0,t,t1 to compute 3 endpoints of 2 chunks and look for the closest point again. You can recursively do this few times as with each iteration you increase precision of the result
The perpendicular distance of point to a line is computed by computing intersection between the line and axis perpendicular to it going through the point in question. So if the line is defined by endpoints p0,p1 and the queried point (mouse) is q then the axis in 2D will be:
dp=p1-p0 // line direction
dq=(dp.y,-dp.x) // axis direction is perpendicular to dp
dq/= |dq| // normalize
p(u) = p0+dp*u // point on line
p(v) = q +dq*v // point on axis
u = <0,1> // parameter on line
v = <-inf,+inf> // parameter on axis
And we want to know u,v from
p0+dp*u = q +dq*v
which is system of 2 linear equations in 2D. In 3D you need to exploit cross product to obtain the dq and the system would contain 3 equations. Solving this sytem will give you u,v where u will tell you where in the chunk the closest point is and |v| is the perpendicular distance itself. Do not forget that if u is not in the range <0,1> then you have to use closer endpoint of the line as the closest point.
The system can be solved either algebraically (but beware the edge cases as there are 2 solutions for the equations in 2D) or use inverse matrix...
There are two main approaches - subdivision of curve into small line segments and analytical solution.
For the second case you have to build polynomial for squared distance from point to curve depending on parameter t, differentiate it, and find zeros of result (5-th order polynomial). Then choose minimum from distances to point at t[i], t=0, t=1.
Another point of view - get projection of point onto curve, so curve tangent in this point is perpendicular to vector point-curvepoint, it should give the same expression.
About uniform points - it is rather hard problem because curve length could not be calculated analytically. But subdivision gives quite good approximation.

margin of error trying to check if a point lays on line

Working with floating point values it is as easy as breathing to run on approximation errors by comparing quantities which should be the same. I want to know if there is a way built in some MSDN (or even external) library for c# to ignore the problem.
An example could be: more than comparing 2 float values like this
if(myVector3.X == anotherVector3.X)
I would appreciate something like this
if(myVector3.X.isInTheNeighbourhood(anotherVector3.X))
This is not well-written, I know. That is just to simplify the explaination. What I am exactly doing is checking if a point (Vector3) lays on line segment. So basically the calculations I make are nothing more than
(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1) = (z - z1)/(z2 - z1)
But these values won't be always the same, so I need to write down some code which includes a sort of tolerance a sort of Neighbourhood mathematical concept to accept values close enought to the line.
Hope that I made myself clear.
Has anyone a solution for this?
I'm proposing the use of an exact predicate. This is an alternative approach to what you actually asked, but it might be worth considering.
Suppose your three points really are at locations indicated by their respective double precision coordinates. A simple double precision computation like the one suggested in your question will likely still return a wrong result. However, there are techniques to obtain exact results to detect these cases. One technique is by turning all numbers into arbitrary precision floating point (or integer) numbers and do most of the computation using integers under the hood. Another, which should work faster on modern hardware, expresses intermediate results as sums of doubles. E.g. when computing a+b, you obtain two resulting numbers, the first is the sum as you'd usually compute it, the other is a correction term to note down the error. In many cases, the bigger terms are sufficient to make a choice, which leads to the concept of adaptive precision.
All of this, including the application to geometric predicates, has been outlined nicely by Jonathan Richard Shewchuk in his page Adaptive Precision Floating-Point Arithmetic and Fast Robust Predicates for Computational Geometry. He has a paper on it, and some C code which should be possible to adapt to C#. Or perhaps to compile in C and link to C#, thus forming a mixed language project. Note however that it makes some assumptions on how the compiler treats floating point computations. In particular, you have to be careful that certain intermediate results don't have excess precision, like the 80-bit numbers stored in a 80387-style floating point unit. I've looked into this myself recently, and the easiest solution might be asking the compiler to use SSE instructions instead of x87 ones.
In your case, you are asking whether a point p lies on the segment connecting p1 and p2. One predicate which would be very much in the spirit of that paper would be the position of a fourth point in relation to a plane spanned by three others: it is either above, below or within that plane, and the orient3d predicate can tell you which. So one possible approach would be taking four arbitrary points q1 through q4 in general position, i.e. not all in a single plane, and no three on a single line. Then you could check whether p,p1,p2,qi are coplanar (sign is zero) for all i ∈ {1,2,3,4}. If they are, then p does at least lie on the line spanned by p1 and p2. Next you could check the orientations of p,p1,qi,qj for different i,j until you find a non-zero sign, then you could see whether p,p2,qi,qj has a different sign. If it does, then p is indeed between p1 and p2, hence on the same line. If you find no i,j such that p,p1,qi,qj is non-zero, then p=p1. Likewise if you have found one non-zero sign, but the corresponding sign of p,p2,qi,qj is zero, then p=p2. It is up to you whether you want to include the endpoints of your line segment. This paragraph might not be the most elegant way to do this, but it leverages the existing orient3d implementation, so it might be easier to use than writing a new predicate from scratch.
Note that in most cases, a point will not exactly lie on a line segment, due to rounding of the point coordinates themselves. The above will only help you to reliably detect those rare cases when it does, so you can deal with them. It may also allow you to make consistent choices for other predicates as well. In the world of CGAL, this approach would be termed “exact predicates, inexact constructions”, since the predicates can be computed reliably, but the geometric objects on which they operate are still subject to approximation. If you really need points that reliably lie on the line segments, and not just close by, then an exact construction approach using some exact number type would be preferable. Or you go with the approaches the other answers suggest.
You need to calculate the distance of the point to the line. That's simple mathematics. Then you decide how far of a distance "close enough" is in your case.
This problem is described as floating-point tolerance in this article and it points out the importance of measuring relative tolerance rather than absolute when comparing large values: http://realtimecollisiondetection.net/blog/?p=89
I've never had a situation where large floating point values are possible so I've always hard-coded a magic value into my comparisons. Eg:
if (Math.Abs(value1, value2) < 0.05f)
{
...
}
Which is "bad" but it works so long as value1 and value2 can't get too big.
In your case you really want to calculate the distance of the point from the line and then check that distance is small enough, rather than testing that the point is exactly on the line. I am rubbish at math myself so don't understand this but let me copy someone else's answer for calculating the shortest distance between a 3D point and a 3D line:
Vector3 u = new Vector3(x2 - x1, y2 - y1, z2 - z1);
Vector3 pq = new Vector3(x3 - x1, y3 - y1, z3 - z1);
float distance = Vector3.Cross(pq, u).Length / u.Length;
3D Perpendicular Point on Line From 3D point

Shortest distance from a point to this curve

I need to find the distance of multiple points to a curve of the form: f(x) = a^(k^(bx))
My first option was using its derivative, using a line of the form with the inverse of the derivative, giving it coordinates of the Point and intersecting it with the original curve. Finally, we calculate the distance between points with simple geometry.
That's the mathematical process that I usually follow. I need to save time (since I'm doing a genetic algorithms program) so I need an efficient way to do this. Ideas?
The distance between a point (c,d) and your curve is the minimum of the function
sqrt((c-x)^2 + (d-a^(k^(bx)))^2)
To find its minimum, we can forget about the sqrt and look at the first derivative. Find out where it's 0 (it has to be the minimal distance, as there's no maximum distance). That gives you the x coordinate of the nearest point on the curve. To get the distance you need to calculate the y coordinate, and then calculate the distance to the point (you can just calculate the distance function at that x, it's the same thing).
Repeat for each of your points.
The first derivative of the distance function, is, unfortunately, a kind of bitch. Using Wolfram's derivator, the result is hopefully (if I haven't made any copying errors):
dist(x)/dx = 2(b * lna * lnk * k^(bx) * a^(k^(bx)) * (a^(k^(bx)) - d) - c + x)
To find distance from point to curve it's not a simple task, for that you need to find the global of function where f(x) is the function which determine your curve.
For that goal you could use:
Simplex method
Nelder_Mead_method
gradient_descent
This methods implemented in many libraries like Solver Foundation, NMath etc.

Categories

Resources