Longest distance between straight line and a curve in UNITY - c#

I've read a lot of questions that were "similar" to mine but no one has been good for me. The thing is that I want to know the longest distance from a curve and a straight line. The curve line is the touch input of the user, every point, and the straight line is from the start touch point to the end touch point.
What's the best and efficient way to achieve that?
Thank you.

Assuming your curve is given by IEnumerable<Point> curve and your line is given by two points start and end.
Func<Point, double> distance = p =>
Math.Abs(
(end.Y - start.Y)*p.X
- (end.X - start.X)*p.Y
+ end.X*start.Y
- end.Y*start.X
)
/ Math.Sqrt(
(end.Y - start.Y)*(end.Y - start.Y)
+ (end.X - start.X)*(end.X - start.X));
Point nearest = curve.OrderBy(distance).First();
Point farthest = curve.OrderByDescending(distance).First();
This is not the most efficient way to do it, because one iteration over the data would suffice and the sorting is overkill. However, there is no builtin ArgMinAndMaxBy in Linq, and speed might not be an issue.
You can, trivially, replace the type Point (from System.Drawing) by your Vector2 type, by the way.

if you are asking which is the longest distance between the straight line and through the curve... the curve has the longest distance.. use the power of calculus where you can estimate the exactly distance of the curve by making use of straight line segments on the curve. the more line segments you can put in higher chance of improved approximation of the distance..

Related

Converting between Bezier Curves of different degree(order)

I'm working on a personal project involving Bezier curves. I have seen many implementations that handle quadratic and cubic curves individually, but I'm looking to create a more generalized algorithm where I can add and remove control points by increasing and decreasing the degree(order) of the curve.
This is not a part of my main question, but if anyone knows an example of a generalized algorithm that I can look at, I will be grateful if they can point me that direction.
First of all, I understand that any conversion from a low order to a high order curve is an approximation, and not equivalent. I am satisfied with computationally "close enough".
Secondly, I also understand that there is a loss of information when stepping down from a higher order to a lower order curve. This is unavoidable as the higher order curve has more "bends" in the curve that the lower order curve simply cannot approximate.
I'm fine with these limitations as it is necessary to be able to add and subtract control points within the curve for desired functionality.
My first question is related to this one asked approximately 5 years ago:
Convert quadratic curve to cubic curve
A quadratic curve has three (3) control points:
Vector3 Start;
Vector3 Control1;
Vector3 End;
The conversion to a cubic we introduce a fourth control point...
Vector3 Control2;
..."Between" Control1 and End. We then set Control1 and Control2 accordingly:
Control2 = new Vector3(
End.x + ((2.0f / 3.0f) * (Control1.x - End.x)),
End.y + ((2.0f / 3.0f) * (Control1.y - End.y)),
End.z + ((2.0f / 3.0f) * (Control1.z - End.z))
);
Control1 = new Vector3(
Start.x + ((2.0f / 3.0f) * (Control1.x - Start.x)),
Start.y + ((2.0f / 3.0f) * (Control1.y - Start.y)),
Start.z + ((2.0f / 3.0f) * (Control1.z - Start.z))
);
I am not certain that this is correct. In the example, only the 'x' component was set. I merely extrapolated 'y' and 'z' from it. If this is not correct, then I'd appreciate knowing what is correct.
This example only covers converting from quadratic to cubic curves. The controlling value appears to be the (2.0f/3.0f) in setting the coordinates. So, does that mean that converting from cubic to quartic would be (2.0f/4.0f) or (3.0f/4.0f) or something else entirely? What is the properly generalized function for this conversion for an arbitrary order of curve?
My project is also going to be working with splines. I am using an edge to edge method for constructing my splines where an edge is defined as an arbitrarily ordered curve from 1 (a line) to n, where the first and last Vector3 in the list of control points are the start and end points of the edge, and connecting edges share the end point of the previous edge with the start point of the next.
Unlike Bezier Curves, I'm not adding and subtracting control points. Instead, I'm dividing and combining edges. What would be a good method for subdividing a curve into two lower order curves with an order no lower than 2 approximating the original curve? Likewise, what would be a good method for combining two curves into a single high order curve?
I realize this is a lot to ask in a single post, but I felt it better to keep it together in one topic rather than dividing it up.
Thanks for any help!
You'll want to read over http://pomax.github.io/bezierinfo/#reordering for how to raising a curve to a higher order, which is almost trivial:
That may look scary, but if you actually look at what each of the three terms is, all three are stupidly simple bits of grade school maths. You typically just want the new weights, so generating those as a new list of coordinates is absolutely trivial and written in about a minute. In Javascript:
function getOneHigher(x, y):
k = x.length;
s = k - 1;
let nx = [], ny =[];
nx[0] = x[0]; nx[k] = x[s];
ny[0] = y[0]; ny[k] = y[s];
for (let i=1; i<k; i++) {
nx[i] = ((k-i)*x[i] + i*x[i-1]) / k;
ny[i] = ((k-i)*y[i] + i*y[i-1]) / k;
}
return {nx, ny};
}
And we're done. Calling getOneHigher(x, y) will yield two arrays of new coordinates for the same curve, represented as a Bezier curve of a degree one higher than we put in. Note that what this means is that we've kept the set of curve coordinates the same (literally: the functions are identical ) while reducing the tangents at each coordinate (because the derivatives are not identical), effectively "slowing down" anything that travels the path that this curve traces.
You'll then also want to follow the link to Sirver's Castle in that section which explains how to do the lossy conversion down in a way that minimizes loss of information. And this should have been multiple questions: this is a Q&A site, future visitors can't find answers to specific questions if you don't ask specific questions but instead combine several technically unrelated ones in a single post.

Which is the more efficient method for calculating the intersections of two circles?

I'm trying to find the fastest and easiest way in a C# program to calculate the intersections of two circles. From what I can tell there are two possible methods, and you'll have to forgive me for not knowing the official names for them.
We're assuming you know the center points for both circles and their exact radii, from which you can calculate the distance between them, so all that is missing are the point(s) of intersection. This is taking place on a standard x-y plot.
The first is a kind of substitution method like the one described here where you combine the two circle formulas and isolate either x or y, then sub it back in to an original formula to end up with a quadratic equation that can be solved for two (or possibly one or none) coordinates for an axis, which then lets you find the corresponding coordinates on the other axis.
The second I have seen a reference to is using a Law of Cosines method to determine the angles, which would then let you plot a line for each side on the grid, and put in your radius to find the actual intersection point.
I have written out the steps for the first method, and it seems rather lengthy. The second one is going to take some research/learning to write out but sounds simpler. What I've never done is translate processes like this into code, so I don't know ultimately which one will be the easiest for that application. Does anyone have advice on that? Or am I perhaps going about the the complete wrong way? Is there a library already out there that I can use for it instead of reinventing the wheel?
Some context: I'm worried mainly about the cost to the CPU to do these calculations. I plan on the application doing a heck of a lot of them at once, repeatedly, hence why I want the simplest way to accomplish it.
Computational geometry is almost always a pain to implement. It's also almost always quite CPU-intensive. That said, this problem is just algebra if you set it up right.
Compute d = hypot(x2-x1, y2-y1), the distance between the two centres. If r1 + r2 < d, there is no intersection. If r1+r2 == d, the intersection is at (x1, y1) + r1/(r1+r2) * (x2-x1,y2-y1). If d < abs(r1-r2), one circle is contained in the other and there is no intersection. You can work out the case where the two circles are tangent and one is contained in the other. I will only deal with the remaining case.
You want to find distances h orthogonal to (x2-x1,y2-y1) and p parallel to (x2-x1,y2-y1) so that p^2 + h^2 = r1^2 and (d-p)^2 + h^2 = r2^2. Subtract the two equations to get a linear equation in p: d^2-2dp = r2^2-r1^2. Solve this linear equation for p. Then h = sqrt(r1^2 - p^2).
The coordinates of the two points are (x1,y1) + p (x2-x1,y2-y1) / d +/- h (y2-y1, x1-x2) / d. If you work through the derivation above and solve for p/d and h/d instead, you may get something that does fewer operations.

Position of coordinate (right-angle) between two Coordinates [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I tell if a point is nearby a certain line?
//Returns the point on the line traced from start to end which
//comes nearest to 500,000, 500,000. The points are scaled between
//1,000,000 and 0 from their original fp types.
Point closestToCentre(Point start, Point end);
Anyone know of quicker way than single stepping through the pixels?
Could some one more alert than me demonstrate their maths & geometry prowess please?
_______EDIT___________
Thanks Kris, this was confusing me :
[x; -a/bx-c/b]=[0; -c/b]-1/b[-b; a]x.
Now I see it is just splitting (mainly the y component) the vector into two which combine to yield the same result. Got the old partial fractions brain cell excited for a minute then :)
_______EDIT_________
Jason Moore, thanks for the inspiration, here is what I am doing, graphically,
I hope that is clearer.
____EDIT________
So I could reasonably expect to take a line at right angles to my sampled line and run it from the centre but how to tell when they touch?
I think Kris's page of equations is the way to go. If you're all telling me it is a two step process. It is just two simultaneous equations now, so I may not need Kris's derivations.
____EDIT_________
Whether good or bad thing, I don't know, but the beauty of stackoverflow as a search engine has revealed to me several routes of investigation. Chiefly I like the first solution here:
Shortest distance between a point and a line segment.
But to prove this to my self I needed the link from matti's solution at the bottom (but one):
http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static
The derivation is so simple and elegant even I could follow it!
Given http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
This is a matter of linear projection of a point onto a line, which can be done with some fine vector gymnastics, as elaborated at MathWorld.
The article details how to find the shortest distance from a point to a line, and one of the intermediate steps is finding the perpendicular line from the point x,y to the original line. Intersecting these two lines will give you the point, on the line, closest to x,y.
Edit in response to comment: What equation (2) in the link is doing is transforming the vector into a form reminiscent of y = mx + c, which allows you to quickly and easily read off the gradient, from which the perpendicular gradient can be easily calculated.
I think the quickest way will be a two step process:
Assume your line is infinite in length, and find the intersection of your line and its perpendicular bisector through (500,000, 500,000).
Make sure that point is actually on your line, else find the closest endpoint.
Kris's post covers step 1 pretty well, all you have to do is add the check for step 2 because you have a line segment and you're golden.
Let point 1 = (x1, y1) and endpoint 2 = (x2, y2). Then the line containing these two points is
y = (y2 - y1)/(x2 - x1) * (x - x1) + y1
and the perp. bisector through (5e5, 5e5) is
y = (x1 - x2)/(y1 - y2) * (x - 5e5) + 5e5
Your point (x,y) is the solution (x,y) to the above two equations (or one of the two endpoints). This might be more straightforward than the mathworld link. Note that this solution fails, however, when your line is either almost vertical or almost horizontal whereas I don't think the mathworld solution style does, though I haven't looked very closely.

Finding angle between two markers for use in mathematical optimisation

I am trying to minimize the difference between sets of square markers in 3d space with a set of unknown parameters.
I have a model set of these square markers (represented by 3d position and rotation) which should at the end of optimization match up with a set of observed square markers.
I am using Levenberg–Marquardt to optimize the set of unknown parameters, these parameters will alter the position and rotation of the model 3d markers until they match (more or less) with the observed 3d marker positions.
The observed 3d markers come from a computer vision marker detection algorithm. It gives the id of the markers seen in each frame and the transformation from the camera of each marker (using Coplanar posit). Each 'frame' would only be able to see a small number of markers in the total set of markers, there will also be inaccuracies in the transformation.
I have thought of how to construct my minimization function and I thought to try to compare the relative rotations and minimize the difference between the rotations in each iteration of the LM optimisation.
Essentially:
foreach (Marker m1 in markers)
{
foreach (Marker m2 in markers)
{
Vector3 eulerRotation = getRotation(m1, m2);
ObservedMarker observed1 = getMatchingObserved(m1);
ObservedMarker observed2 = getMatchingObserved(m2);
Vector3 eulerRotationObserved = getRotation(observed1, observed2);
double diffX = Math.Abs(eulerRotation.X - eulerRotationObserved.X);
double diffY = Math.Abs(eulerRotation.Y - eulerRotationObserved.Y);
double diffZ = Math.Abs(eulerRotation.Z - eulerRotationObserved.Z);
}
}
Where diffX, diffY and diffZ are the values to be minimized.
I am using the following to calculate the angles:
Vector3 axis = Vector3.Cross(getNormal(m1), getNormal(m2));
axis.Normalize();
double angle = Math.Acos(Vector3.Dot(getNormal(m1), getNormal(m2)));
Vector3 modelRotation = calculateEulerAngle(axis, angle);
getNormal(Marker m) calculates the normal to the plane that the square marker lies on.
I am sure I am doing something wrong here though. Throwing this all into the LM optimiser (I am using ALGLib) doesn't seem to do anything, it goes through 1 iteration and finishes without changing any of the unknown parameters (initially all 0).
I am thinking that something is wrong with the function I am trying to minimize over. It seems sometimes the angle calculated (3rd line) returns NaN (I am currently setting this case to return diffX, diffY, diffZ as 0). Is it even valid to compare the euler angles as above?
Any help would be greatly appreciated.
Further information:
Program is written in C#, I am using XNA as well.
The model markers are represented by its four corners in 3D coords
All the model markers are in the same coordinate space.
Observed markers are the four corners as translations from the camera position in camera coordinate space
If m1 and m2 markers are the same marker id or if either m1 or m2 is not observed, I set all the diffs to 0 (no difference).
At first I thought this might be a typo, but then I realized that this could be a bug, having been a victim of similar cases myself in the past.
Shouldn't diffY and diffZ be:
double diffY = Math.Abs(eulerRotation.Y - eulerRotationObserved.Y);
double diffZ = Math.Abs(eulerRotation.Z - eulerRotationObserved.Z);
I don't have enough reputation to post this as a comment, hence posting it as an answer!
Any luck with this? Is it correct to assume that you want to minimize the "sum" of all diffs over all marker combinations? I think if you want to use LM you should not use Math.Abs.
One alternative would be to formulate your objective function manually and use another optimizer. I have recently ported two non-linear optimizers to C# which do not even require you to compute derivatives:
COBYLA2, supports non-linear constraints but require more iterations.
BOBYQA, limited to variable bounds constraints, but provides a considerable more efficient iteration scheme.

projection of point on line in 3D

I have point with x,y,z
and line direction x,y,z
how to get the point projection on this line
I tried this code
http://www.zshare.net/download/93560594d8f74429/
for example when use the function intersection in the code I got
the line direction is (1,0,0) and the point (2,3,3) will have projection (value in x , 0, 0 ) and this is wrong value
any suggestion
Best regards
You want to project the vector (x,y,z) on the line with direction (a,b,c).
If (a,b,c) is a unit vector then the result is just (x,y,z).(a,b,c) (a,b,c) = (ax+by+cz)(a,b,c)
If it's not a unit vector make it one, divising it by its norm.
EDIT : a little bit of theory:
Let E be your vectorial space of dimension N:
let F be the line directed by vector a. The hyperplan orthogonal to F is :
Now let's chose a vector x in E, x can be writen as :
where xF is the coordinate of x in the direction of F, an x orthogonal is the coordinate on the orthogonal hyperplan.
You want to find xF: (it's exactly the same formula as the one I wrote above)
You should have a close look at the wikipedia article on orthogonal projections and try to find more stuff on the web .
You can generalise that to any F, if it's not a line anymore but a plan then take F orthogonal and decompose x the same way...etc.
This topic is clearly old and I think the original poster meant vector not line. But for the purposes of Google:
A line, unlike a vector does not (necessarily) have its origin at (0,0,0). So cannot be described just by a direction, it also needs an origin. This is the zero point of the line; the line can extend beyond and before this point, but when you say you’re zero meters along the line this is where you mean.
So to get the projection of a point onto a line you first need to convert the point into the local co-ordinate frame, which you do by subtracting the origin from the point (e.g. if a fence post is the ‘line’ you go from GPS co-ordinates to ‘5 metres to the north and a meter above the bottom of the fence post‘). Now in this local co-ordinate frame the line is just a vector, so we can get the projection of the point using the normal dot product approach.
pointLocalFrame = point– origin
projection = dotProduct(lineDirection, pointLocalFrame)
NOTE: this assumes the line is infinite in length, if the projection is greater than the actual line length then there is no projection
NOTE: lineDirection must be normalised; i.e. its length must be 1
NB: dot product of two vectors (x1,y1,z1) and (x2,y2,z2) is x1*x2+y1*y2+z1*z2

Categories

Resources