douglas-peucker algorithm: understanding use with polgyons - c#

I've been going over this algorithm and it seams pretty straight forward. I am, however, confused as to how to use it in a enclosed polygons. ALL of the examples I have seen deal with a line/curve with open ends. If i'm visualizing the process correctly drawing a single line and then iterating over it to re-capture the detail of a polygon wont work because it will always leave at least on side of the polygon open.
I'm thinking about writing an implementation that first makes 4 points (the farthest topLeft, TopRight, Bottomright, and BottomLeft points) and then runs the algorithm on vertices in between these to points indices.
So if the bottom line has an index of 40 and 80 in the original path array then I will iterate there and capture the likeness of that line on just points 40-80 them move onto the next side until all for sides are done.
I've been known to make a fool myself and way overcomplicate tings so I was wondering if this was a reasonable implementation?
I'm basicaly trying to replication the GPX data reduction impmentation seen below:

After a quick reading of the algorithm on Wikipedia, it seems that you can capture the simplified shape of the enclosed loop in a simple way.
Call the method with the start-point 'A' and end-point 'Z' being the same.
Modify the algorithm, so that if 'A' and 'Z' are the same point that instead of finding the farthest point perpendicular to the line AZ that it just looks for the point farthest away according to Euclidean distance from the Start/End point.
Now the algorithm recurses on A->M and M->Z where M is the point farthest from A (which is also Z). Now the algorithm can run normally.

Related

How do I find the control points for a Bezier curve?

I need to implement connections in the form of curved lines in C# (Unity). I would like to get the result as similar as possible to the implementation in Miro.com (see screenshot).
After attaching the curve, I calculate the path of the cubic Bezier curve. For this first segment, the anchor points and offsets from the objects it connects are used. There are no problems at this stage.
Problem: When dividing the curve into segments by clicking and dragging one of the blue points of the segment (see screenshot), it is split in two in the middle. At the junction of two new curves, a new interactive (movable) point is formed for which the tangent and coordinates of the control points are unknown. I need to find the position of these control points every time the position of the interactive points changes (white points in the picture below). Moreover, the curve should not drastically change its position when dividing, not form loops, have different lengths of control point vectors (I'm not sure here) and behave as adequately as possible (like on the board in Miro).
By control points I mean 2 invisible guide points for the Bezier segment.
In black I painted the known control points, and in red those that I need to find. (Pn - interactive points, Cn - control points)
The algorithms I have tried to find them give incorrect distances and directions of control points.
The following algorithms were tested:
Interpolation from Tacent - jumps of the curve when separating, inappropriate direction and amount of indentation of control points;
Chaikin's algorithm - curve jumps during separation, creates loops;
"Custom" interpolation based on guesses (takes into account the distance to the center of the segment between the start and end points of the segment, as well as the direction between the start and end points) - has all the same problems, but looks slightly better than those above.
I suspect the solution is to chordally interpolate the points using a Catmull-Rom spline and translate the result to points for a Bezier curve. However, there are still problems with implementation.
The curves from 3DMax also look very similar. In their documentation, I found only a mention of the parametric curve.
Methods that I did not use (or did not work):
Catmull-Rom interpolation;
B-spline interpolation;
Hermitian interpolation;
De Casteljau's algorithm (although it seems not for this)
I would be immensely grateful for any help, but I ask for as much detail as possible.
Find helpful sources to understand bezier curves here and here.
To do what you want, I would give a try to the Catmull-Rom approach which I believe is much more simple than Bezier's, which is the one used in the itween asset, that is free, and you got plenty of funtionality implemented.
If you want to stick to the bezier curves and finding the control points, I will tell you what I would do to find them.
For the case of 2 control point bezier curve:
P = (1-t)P1 + tP2
To get to know the control points P1(x1,y1) and P2(x2,y2), you need to apply the equation in a known point of your curve. Take into account that the 2D equation is vectorial, so each points provides 2 equations one for x and one for y, and you got 4 unknows, x and y for each point.
So for the first node of the curve (t=0), you would have:
Px = (1-0)P1x + 0*P2x
Py = (1-0)P1y + 0*P2y
For the last point (t=1)
Px = (1-1)P1x + 1*P2x
Py = (1-1)P1y + 1*P2y
With these 4 equations I would try to achieve the control points P1 and P2. You can do it with t=0 and t=1 which are the supposed points you know of your curve and the ones that simplify the math due to the t values, but you should be able to use any as long as you know the points coords in the curve for determined t.
If the curve is a 3 control point bezier, you would need 6 equations for the 3 control points and so on.
I think that the best approach is to compound the curve of cuadratic curves composition, and calculate the control points for each chunk, but I am not sure about this.
Once maths are understood and control points achieved, In case that was successful I would try to implement that in the code.

Point in Polytope aka Hit Test

There are a set of points S in n dimensional space. I want to test a given point P is inside the region of S.
Since this is n dimensional space, points should form a polytope. Then the question is to determine whether a given point is inside the convex polytope.
I find this for 3-D polyhedrons but C++ libraries were not meaningful and I couldn't find their definitions. Besides it doesn't check the boundary conditions.
Another algorithm I found is for 2D polygons. I couldn't modify it since it is not clearly written. I can extend it of course but I'm not an expert in this domain so it's better to ask first.
Finally I found an algorithm for triangulation for concave polygon but I don't think it fits to my case.
Not sure what exactly you are asking, it seems you have several problems. First to compute Convex Hull of a point set. In 2d you can use BOOST or CGAL. For 3d CGAL. Not sure if they handle higher dimensions. For interior check, one way is (as the link you posted states) to check the ray intersection from the point of query to a known exterior point. The point of intersection of the ray (for interior point) should lie on a plane with normal pointing in the same direction as your ray. Meaning you are exiting the volume. A more efficient way would be to use something like a Binary Space Partitioning Tree (BSP). There are many links with tutorials on how that works.
From your description, you have established that S is convex. If that is the case you apply the hyperplane separation theorem (http://en.wikipedia.org/wiki/Hyperplane_separation_theorem)
Find the point Q in S that is closest to P.
Construct a hyperplane H that lies on Q and is normal to P-Q
Test all the points in S on which side of H are on.
If they are all either on the plane or on the opposite side of H compared to P, then P is either on or outside of S. If some points are in front of H, and others are behind H, then P is inside S.

How to smooth out WPF line segment of path figure

The below is Android code.
path.moveTo(xx, yy);
for (...) {
path.lineTo(xx, yy);
}
canvas.drawPath(this.path, paint);
In order to remove the sharp corner, I am using
final CornerPathEffect cornerPathEffect = new CornerPathEffect(50);
paint.setPathEffect(cornerPathEffect);
When comes to WPF, I am using the following code.
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = new Point(xx, yy);
for (...) {
LineSegment lineSegment = new LineSegment(new Point(xx, yy), true);
lineSegment.IsSmoothJoin = true;
pathFigure.Segments.Add(lineSegment);
}
PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { pathFigure });
drawingContext.DrawGeometry(null, new Pen(Brushes.White, 3), pathGeometry);
I am getting the following effect.
Note that, I avoid from using PolyQuadraticBezierSegment or PolyBezierSegment. It tend to become unstable. This means, whenever I add a new incoming point to the line graph, the newly added point will tend to change the old path, which is already drawn on the screen. As an end effect, you may observer the whole line graph is shaking
May I know in WPF, how I can smooth out the line segment? Although I have used lineSegment.IsSmoothJoin = true;, I still can see the sharp corner. Can I have something equivalent to Android's CornerPathEffect?
I know, zombie thread post. You probably already solved this problem, but here are my thoughts years after the fact...
Since smoothing is dependent on multiple points in the line I think it will be quite difficult to find a smoothing algorithm that looks reasonable without producing some instability in the leading edge. You can probably reduce the scope of the instability, but only at risk of producing a very odd looking trace.
First option would be to use a spline algorithm that limits the projection artifacts. For instance the Catmull-Rom algorithm uses two known points on either side of the curve segment being interpolated. You can synthesize two additional points at each end of the curve or simply draw the first curve segment as a straight line. This will give a straight line as the last segment, plus a curve as the second to last segment which should change very little if at all when another point is added.
Alternatively you can run the actual data points through an initial spline calculation to multiply the points, then run those points through the spline algo a second time. You'll still have to update the most recent 2m points (where m is the multiplier of the first pass) or the output will look distorted.
About the only other option I can think of is to try to predict a couple of points ahead based on your prior data, which can be difficult even with a fairly regular input. I used this to synthesize Bezier control points for the ends of my curves - I was calculating CPs for all of the points and needed something to use for the end points - and had some interesting times trying to stop the final curve segments from looking horribly deformed.
Oh, one more... don't graph the final curve segment. If you terminate your curve at Pn-1 the curve should stay stable. Draw the final segment in a different style if you must show it at all. Since C-R splines only need +/- 2 known points from the interpolation the segment Pn-2-Pn-1 should be stable enough.
If you don't have code for the C-R algorithm you can do basically the same thing with synthetic Bezier control points. Rather than attempt to describe the process, check out this blog post which gives a fairly good breakdown of the process. This article has code attached which may be useful.

Simple way to calculate point of intersection between two polygons in C#

I've got two polygons defined as a list of Vectors, I've managed to write routines to transform and intersect these two polygons (seen below Frame 1). Using line-intersection I can figure out whether these collide, and have written a working Collide() function.
This is to be used in a variable step timed game, and therefore (as shown below) in Frame 1 the right polygon is not colliding, it's perfectly normal for on Frame 2 for the polygons to be right inside each other, with the right polygon having moved to the left.
My question is, what is the best way to figure out the moment of intersection? In the example, let's assume in Frame 1 the right polygon is at X = 300, Frame 2 it moved -100 and is now at 200, and that's all I know by the time Frame 2 comes about, it was at 300, now it's at 200. What I want to know is when did it actually collide, at what X value, here it was probably about 250.
I'm preferably looking for a C# source code solution to this problem.
Maybe there's a better way of approaching this for games?
I would use the separating axis theorem, as outlined here:
Metanet tutorial
Wikipedia
Then I would sweep test or use multisampling if needed.
GMan here on StackOverflow wrote a sample implementation over at gpwiki.org.
This may all be overkill for your use-case, but it handles polygons of any order. Of course, for simple bounding boxes it can be done much more efficiently through other means.
I'm no mathematician either, but one possible though crude solution would be to run a mini simulation.
Let us call the moving polygon M and the stationary polygon S (though there is no requirement for S to actually be stationary, the approach should work just the same regardless). Let us also call the two frames you have F1 for the earlier and F2 for the later, as per your diagram.
If you were to translate polygon M back towards its position in F1 in very small increments until such time that they are no longer intersecting, then you would have a location for M at which it 'just' intersects, i.e. the previous location before they stop intersecting in this simulation. The intersection in this 'just' intersecting location should be very small — small enough that you could treat it as a point. Let us call this polygon of intersection I.
To treat I as a point you could choose the vertex of it that is nearest the centre point of M in F1: that vertex has the best chance of being outside of S at time of collision. (There are lots of other possibilities for interpreting I as a point that you could experiment with too that may have better results.)
Obviously this approach has some drawbacks:
The simulation will be slower for greater speeds of M as the distance between its locations in F1 and F2 will be greater, more simulation steps will need to be run. (You could address this by having a fixed number of simulation cycles irrespective of speed of M but that would mean the accuracy of the result would be different for faster and slower moving bodies.)
The 'step' size in the simulation will have to be sufficiently small to get the accuracy you require but smaller step sizes will obviously have a larger calculation cost.
Personally, without the necessary mathematical intuition, I would go with this simple approach first and try to find a mathematical solution as an optimization later.
If you have the ability to determine whether the two polygons overlap, one idea might be to use a modified binary search to detect where the two hit. Start by subdividing the time interval in half and seeing if the two polygons intersected at the midpoint. If so, recursively search the first half of the range; if not, search the second half. If you specify some tolerance level at which you no longer care about small distances (for example, at the level of a pixel), then the runtime of this approach is O(log D / K), where D is the distance between the polygons and K is the cutoff threshold. If you know what point is going to ultimately enter the second polygon, you should be able to detect the collision very quickly this way.
Hope this helps!
For a rather generic solution, and assuming ...
no polygons are intersecting at time = 0
at least one polygon is intersecting another polygon at time = t
and you're happy to use a C# clipping library (eg Clipper)
then use a binary approach to deriving the time of intersection by...
double tInterval = t;
double tCurrent = 0;
int direction = +1;
while (tInterval > MinInterval)
{
tInterval = tInterval/2;
tCurrent += (tInterval * direction);
MovePolygons(tCurrent);
if (PolygonsIntersect)
direction = +1;
else
direction = -1;
}
Well - you may see that it's allways a point of one of the polygons that hits the side of the other first (or another point - but thats after all almost the same) - a possible solution would be to calculate the distance of the points from the other lines in the move-direction. But I think this would end beeing rather slow.
I guess normaly the distances between frames are so small that it's not importand to really know excactly where it hit first - some small intersections will not be visible and after all the things will rebound or explode anyway - don't they? :)

Getting curve details from points

I have a List of 2D points. What's an efficient way of iterating through the points in order to determine whether the list of points are in a straight line, or curved (and to what degree). I'd like to avoid simply getting slopes between smaller subsets. How would I go about doing this?
Thanks for any help
Edit: Thanks for the response. To clarify, I don't need it to be numerically accurate, but I'd like to determine if the user has created a curved shape with their mouse and, if so, how sharp the curve is. The values are not too important, as long as it's possible to determine the difference between a sharp curve and a slightly softer one.
If you simply want to know if all your points fit more or less on a curve of degree d, simply apply Lagrange interpolation on the endpoints and d-2 equally spaced points from inside your array. This will give you a polynomial of degree d.
Once you have your curve, simply iterate over the array and see how far away from the curve each point is. If they're farther than a threshold, your data doesn't fit your degree d polynomial.
Edit: I should mention that iterating through values of d is a finite process. Once d reaches the number of points you have, you'll get a perfect fit because of how Lagrange interpolation works.
To test if it's a straight line, compute the correlation coefficient. I'm sure that's covered on wikipedia.
To test if it's curved is more involved. You need to know what kind of curves you expect, and fit against those.
Here is a method to calculate angle: Calculate Angle between 2 points using C#
Simply calculate angle between each and every point in your list and create list of angles, then compare if angles list values are different. If they are not different then it means it's straight line, otherwise it's curve...
If it's a straight line then angle between all points has to be a same.
The question is really hazy here: "I'd like to avoid simply getting slopes between smaller substes"
You probably want interpolation a-la B-splines. They use two points and two extra control points if memory serves me. Implementations are ubiquitous since way back (at least 1980's). This should get you underway
Remember that you'll probably need to add control points to make the curve meet the endpoints. One trick to make sure those are reached is to simply duplicate the endpoints as extra controlpoints.
Cheers
Update Added link to codeproject
it would appear that what I remember from back in the 80's could have been Bezier curves - a predecessor of sorts.

Categories