I would like to implement the Ramer–Douglas–Peucker_algorithm in C++.
The pseudo code looks like this:
function DouglasPeucker(PointList[], epsilon)
//Find the point with the maximum distance
dmax = 0
index = 0
for i = 2 to (length(PointList) - 1)
d = OrthogonalDistance(PointList[i], Line(PointList[1], PointList[end]))
if d > dmax
index = i
dmax = d
end
end
//If max distance is greater than epsilon, recursively simplify
if dmax >= epsilon
//Recursive call
recResults1[] = DouglasPeucker(PointList[1...index], epsilon)
recResults2[] = DouglasPeucker(PointList[index...end], epsilon)
// Build the result list
ResultList[] = {recResults1[1...end-1] recResults2[1...end]}
else
ResultList[] = {PointList[1], PointList[end]}
end
//Return the result
return ResultList[]
end
Here is my understanding so far.
It is a recursive function taking in an array of points and a distance threshold.
Then it iterates through the current points to find the point with the maximum distance.
I got a bit lost with the Orthographical Distance function. How do I compute this? I've never seen a distance function take a line segment as a parameter.
I think aside from this I should be alright, I will just use std::vectors for the arrays. I think I will use std::copy and then push or pop according to what the algorithm says.
Thanks
The OrthogonalDistance is shown in this picture:
So it's the distance from your point and the point on the line which is the projection of that point on the line.
The distance from a point to a line is usally something like this:
(source: fauser.edu)
where x0 and y0 are the coordinates of the external point and a, b, c are the coefficient of the equation of your line.
That's what I remember from school, long time ago.
The orthogonal distance from a point P to a line L is defined by the distance between point P and point P2, where P2 is the orthogonal projection of P on line L.
How you compute this value depends on the dimension of the space you work on, but if it's 2D, you should be able to figure that out by drawing an example on a piece of paper !
Look at the topcoder tutorial and the
double linePointDist(point A, point B, point C, bool isSegment);
method it it what your looking for.
A brief description of the math required can be found here. Just realize that you can swap the word "Orthogonal" for "Perpendicular" when dealing with 2D. The site linked has instructions for lines defined by two points as well as lines defined by slope-intercept form.
The short version is reproduced here:
If the line is represented in slope intercept from: ax + by + c = 0, and the point is represented by x0, y0, then the function that will give the Orthogonal distance is:
abs(a*x0 + b*y0 + c)/sqrt(a*a + b*b)
It's not clear to me whether you want the distance of the point to the (infinite) line through the two points, or the distance to the line segment defined by the points, but I suspect its the latter.
Consider the somewhat contrived example of the points (0,0) (1,0) and (10, t) where t is small. The distance of (10,t) from the line through the first two points (ie the x axis) is t, while the distance (10,t) from the line segment with end points (0,0) and (1,0) is hypot(9,t) ~ 9. So if you were using distance to the line, there is a danger that the
algorithm above would not split at (10,t).
The method mentioned by jethro above handles both lines and line segments.
Related
I am working on a C++ problem where I'm trying to make a utility function func() that takes as input two line segments starting points in 3d space [(x,y,z) and radius r]. If the segments can be oriented such that they end at the same point, the function should return true and print out that point. If there are multiple orientations that would produce a common endpoint, the function should choose the one that is furthest in the direction indicated by hint_direction.
The function receives these values:
bool func(
point3d position_0, // origin of first line segment.
float length_0, // length of first line segment.
point3d position_1, // origin of second line segment.
float length_1, // length of second line segment.
vector3d hint_direction, // in the event there are multiple solutions, return the one furthest in this direction.
point3d *out_common_end_position) // if result is true, point where both line segments can be oriented to end. otherwise uninitialized.
I am working on one of the first edge cases; where there is a single intersection point such as in the image below.
(image link = https://i.stack.imgur.com/dh9Vr.png)
My code correctly identifies this edge case, but I'm not sure how to programmatically find this intersection point.
//calling function with example from image above, cords, radius, and hint
bool result = func({1, 1, 0}, 1.0, {3, 1, 0}, 1.0, {0, 0, 1}, &common_end_position);
bool func(point3d position_0, float length_0, point3d position_1, float length_1,vector3d hint_direction,point3d *out_common_end_position){
//if statement detecting single intersection
if(length_0 + length_1 == d){
printf("intersection at a single point\n");
//find single intersection point (?)
}
I have been following some guides online which lay out how to do this such as this:
https://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection
Which says: "If r_1 + r_2 == d, then the intersection is a single point, located a distance of r_1 on the line from c_1 to c_2, or: c_i = c_1 + (c_2 - c_1) * r_1/d"
It's been a long time since I've done geometry like this, if I want to find the single point of intersection, how do I do that with the equation above "c_i = c_1 + (c_2 - c_1) * r_1/d" ? I understand that c_2 - c_1 is the distance between both centers which I have computed earlier in my program as float d, but I'm sure sure what's meant by "c_1 + " since c_1 refers to the whole set of cords (x,y,z).
Overall, I'm trying to find a way to get the single intersection point for example such as in my image, could somebody please help em understand the linked solution above? I am going to continue to research solutions in the meantime. Thank you.
I understand that c_2 - c_1 is the distance between both centers
Incorrect. c_2 - c_1 is the vector (in the geometry sense, not the c++ sense) that describes the direction from c_1 to c_2 and which has magnitude d. (c_2 - c_1)/d is therefore the unit vector that describes the direction from c_1 to c_2.
(c_2 - c_1)/d * r_1 is therefore the point on the line between c_1 and c_2 that is distance r_1 from c_1, or, the intersection point of the circles.
but I'm sure sure what's meant by "c_1 + " since c_1 refers to the whole set of cords (x,y,z).
c_1 is not the whole set of points on the circle. c_1 is the center of circle 1.
Also keep in mind that you're dealing with floats. As such, it is subject to floating point errors. Looking for an exact equality in cases like this is subject to error. Consider that looking to see if d is within some acceptable error tolerance of r1 + r2 might be more appropriate
((r1 + r2 - e) <= d && d <= (r1 + r2 + e))
instead of
d == r1 + r2
I am currently looking to implement an algorithm that will be able to compute the arc midpoint. From here on out, I will be referring to the diagram below. What is known are the start and end nodes (A and B respectively), the center (point C) and point P which is the intersection point of the line AB and CM (I am able to find this point without knowing point M because line AB is perpendicular to line CM and thus, the slope is -1/m). I also know the arc angle and the radius of the arc. I am looking to find point M.
I have been looking at different sources. Some suggest converting coordinates to polar, computing the mid point from the polar coordinates then reverting back to Cartesian. This involves sin and cos (and arctan) which I am a little reluctant to do since trig functions take computing time.
I have been looking to directly computing point M by treating the arc as a circle and having Line CP as a line that intersects the circle at Point M. I would then get two values and the value closest to point P would be the correct intersection point. However, this method, the algebra becomes long and complex. Then I would need to create special cases for when P = C and for when the line AB is horizontal and vertical. This method is ok but I am wondering if there are any better methods out there that can compute this point that are simpler?
Also, as a side note, I will be creating this algorithm in C++.
A circumference in polar form is expressed by
x = Cx + R cos(alpha)
y = Cy + R sin(alpha)
Where alpha is the angle from center C to point x,y. The goal now is how to get alpha without trigonometry.
The arc-midpoint M, the point S in the middle of the segment AB, and your already-calculated point P, all of them have the same alpha, they are on the same line from C.
Let's get vector vx,vy as C to S. Also calculate its length:
vx = Sx - Cx = (Ax + Bx)/2 - Cx
vy = Sy - Cy = (Ay + By)/2 - Cy
leV = sqrt(vx * vx + vy * vy)
I prefer S to P because we can avoid some issues like infinite CP slope or sign to apply to slope (towards M or its inverse).
By defintions of sin and cos we know that:
sin(alpha) = vy / leV
cos(alpha) = vx / leV
and finally we get
Mx = Cx + R * vx / leV
My = Cy + R * vy / leV
Note: To calculate Ryou need another sqrt function, which is not quick, but it's faster than sin or cos.
For better accuracy use the average of Ra= dist(AC) and Rb= dist(BC)
I would then get two values
This is algebraically unavoidable.
and the value closest to point P would be the correct intersection point.
Only if the arc covers less than 180°.
Then I would need to create special cases for when P = C
This is indeed the most tricky case. If A, B, C lie on a line, you don't know which arc is the arc, and won't be able to answer the question. Unless you have some additional information to start with, e.g. know that the arc goes from A to B in a counter-clockwise direction. In this case, you know the orientation of the triangle ABM and can use that to decide which solition to pick, instead of using the distance.
and for when the line AB is horizontal and vertical
Express a line as ax + by + c = 0 and you can treat all slopes the same. THese are homogeneous coordinates of the line, you can compute them e.g. using the cross product (a, b, c) = (Ax, Ay, 1) × (Bx, By, 1). But more detailed questions on how best to compute these lines or intersect it with the circle should probably go to the Math Stack Exchange.
if there are any better methods out there that can compute this point that are simpler?
Projective geometry and homogeneous coordinates can avoid a lot of nasty corner cases, like circles of infinite radius (also known as lines) or the intersection of parallel lines. But the problem of deciding between two solutions remains, so it probably doesn't make things as simple as you'd like them to be.
I have an NxN grid with 2 points, the source and destination. I need to move step by step from the source to the destination (which is also moving). How do I determine what the next point is to move to?
One way is to assess all 8 points and see which yields the lowest distance using an Euclidian distance. However, I was hoping there is a cool (mathematical) trick which will yield more elegant results.
Your question statement allows moving diagonally, which is faster (since it's moving both horizontally and vertically in a single step): this solution will always do that unless it has the same x or y coordinate as the target.
using Position = pair<int,int>;
Position move(Position const ¤t, Position const &target) {
// horizontal and vertical distances
const int dx = target.first - current.first;
const int dy = target.second - current.second;
// horizontal and vertical steps [-1,+1]
const int sx = dx ? dx/abs(dx) : 0;
const int sy = dy ? dy/abs(dy) : 0;
return { current.first + sx, current.second + sy };
}
I'm not sure if this counts as a cool mathematical trick though, it just depends on knowing that:
dx = target.x-current.x is positive if you should move in the positive x-direction, negative if you should go in the negative direction, and zero if you should go straight up/down
dx/abs(dx) keeps the sign and removes the magnitude, so it's always one of -1,0,+1 (avoiding however division by zero)
I suppose that answer to your question is Bresenham's line algorithm. It allows to build sequence of integer points between start and end points in your grid. Anyway you can adapt ideas from it to your problem
For more information see https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
I would simply use some vector math, take dest minus source as a vector, and then calculate the angle between that vector and some reference vector, e.g. <1, 0>, with standard methods.
Then you can simply divide the circle in 8 (or 4 if your prefer) sections and determine in which section your vector lies from the angle you obtained.
See euclidean space for how to calculate the angle between two vectors.
I need to determine points of inflection (points where the curvature changes) on a 2d Bezier curve, parameterized by t, 0 <= t <= 1, if they exist. My original method was to sample along the curve, evaluating second derivatives and finding the point where the derivative's sign changes.
2DVector curvature1, curvature2;
for (double t = 0, t <= 1.0; t += STEP) {
curvature1 = bezier.CurvatureAt(t);
curvature2 = bezier.CurvatureAt(t + (STEP/2.0 >= 1.0 ? 0 : t + STEP/2.0));
if (isNegative(curvature1) ? isPositive(curvature2) : isNegative(curvature2)) {
inflection_point = t;
}
}
where CurvatureAt() is a method that evaluates the second derivative of the bezier at t, but as the bezier curve is a vector valued function the derivative is returned as a 2D vector (not std::vector, a 2D vector class). I dont know how to interpret "where the sign changes" for vectors. Basically i dont know how to write isNegative or isPositive in the above snippet.
are there any other ways to find points of inflection on a 2d Bezier curve?
I dont think its possible to determine a closed form solution to this problem because the Bezier can be of arbitrary degree, however please correct me if I'm wrong here.
Curvature is related to but not the same as second derivative.
The signed curvature of a parametric curve P(t) = (x(t), y(t)) is actually a number and is defined as:
k(t) = (x'y'' - x''y') / (x' * x' + y' * y')^(3/2)
If you use this formula your original idea should work.
To determine the points of inflection on a bezier, find the time or times in the interval (0, 1) [excluding the endpoints of course] for which the cross product of the first and second derivatives of the parametric equation of the bezier is zero i.e. f' X f'' = 0.
This is noted in various sources like this page and p 4 of this paper.
I think you don't need such a loop.
According to this page, you can compute at any point the curvature of a Bezier curve. As a Bezier curve has a polynomial expression, you can easily compute when the sign of the curvature changes.
I have a parametric curve, say two vectors of doubles where the parameter is the index, and I have to calculate the angle of the tangent to this curve at any given point (index).
Any suggestion or link about how to do that?
Thanks.
Here's a short formula, equivalent (I think) to pau.estalella's answer:
m[i] = (y[i+1] - y[i-1]) / (x[i+1] - x[i-1])
this approximates, reasonably well, the slope at the point (x[i], y[i]).
Your question mentions the "angle of the tangent". The tangent line, having slope m[i], makes angle arctangent(m[i]) with the positive x axis. If this is what you're after, you might use the two-argument arctangent, if it's available:
angle[i] = atan2(y[i+1] - y[i-1], x[i+1] - x[i-1])
this will work correctly, even when x[i+1] == x[i-1].
I suggest you check out the Wikipedia article on numerical differentiation for a start. Before you go much further than that, decide what purposes you want the tangent for and decide whether or not you need to try more complex schemes than the simple ones in the article.
The first problem you run into is to even define the tangent in one of the vertexes of the curve. Consider e.g. that you have the two arrays:
x = { 1.0, 2.0, 2.0 };
y = { 1.0, 1.0, 2.0 };
Then at the second vertex you have a 90-degree change of direction of the line. In that place the tangent isn't even defined mathematically.
Answer to gregseth's comment below
I guess in your example the "tangent" at the second point would be the line parallel to (P0,P2) passing through P1... which kind of give me the answer : for any point of index N the parallel to (N-1, N+1) passing through N. Would that be a not-too-bad approximation?
It depends on what you are using it for. Consider for example:
x = { 1.0, 2.0, 2.0 };
y = { 1.0, 1000000, 1000000 };
That is basically an L shape with a very high vertical line. In your suggestion it would give you an almost vertical tangent. Is that what you want, or do you rather want a 45-degree tangent in that case? It also depends on your input data how you sould define it.
One solution is get the two vectors connection to the vertex, normalize them and then use your algorithm. That way you would get a 45-degree tangent in the above example.
Compute the first derivative: dy/dx. That gives you the tangent.
The tangent to a smooth curve at a point P is the parametric straight line P + tV, where V is the derivative of the curve with respect to "the parameter". But here the parameter is just the index of an array, and numerical differentiation is a difficult problem, hence to approximate the tangent I would use (weighted) least squares approximation.
In other words, choose three or five points of the curve around your point of interest P (i.e. P[i-2], P[i-1], P[i], P[i+1], and P[i+2], if P==P[i]), and approximate them with a straight line, in the least squares sense. The more weight you assign to the middle point P, the more close the line will be to P; on the other hand, the more weight you assign to the extremal points, the more "tangent" the straight line will be, that is, the more nicely it will approximate you curve in the neighborhood of P.
For example, with respect to the following points:
x = [-1, 0, 1]
y = [ 0, 1, 0]
for which the tangent is not defined (as in Anders Abel's answer),
this approach should yield a horizontal straight line close to the point (0,1).
You can try to compute the tangent of an interpolating curve that passes through the given points (I'm thinking of a cubic spline, which is pretty easy to derive) or compute the tangent directly from the data points.
You can find a rough approximation of the derivative in the following manner
Let a curve C pass through points p1,p2 and p3. At point p2 you have two possible tangents: t1=p2-p1 and t2=p3-p2. You can combine them by simply computing their average: 0.5*(t1+t2)
or you can combine them according to their lengths (or their reciprocal 1/length)
Remember to normalize the resulting tangent.
In order to compute the angle between the tangent and the curve, remember that the dot product of two unit vectors gives the cosine of the angle between them. Take the resulting tangent t and the unit vector v2=|p3-p2|, and acos(dot(t,v2)) gives the angle you need.