I need to implement a chart to represent data on a simple X,Y axis, X being time.
Think of e.g. speedtest or RAM usage over time.
When I start drawing, I have no data. As time passes by, more data comes to my set and I can use it to draw chart. Given that I have 1 [X,Y] coordinate for every second, I want to draw this as a continuous line.
Obviously, Bezier curves came to my mind, but the problem is that my points are always changing. At one second I have N points, in the next one N+1. And if I decide to work only with the last M points, this will not be a continuous line. Every time I add a new last point P to my Bezier curve, it changes the curve as a whole, not just the part between P and P-1.
So what is the correct approach to this problem? Is Bezier curve a viable solution with some hack, or do I have to use some other approach?
Thanks!
Related
I have lat/lng data of multirotor UAV flights. There are alot of datapoints (~13k per flight) and I wish to find line segments from the data. They give me flight speed and direction. I know that most of the flights are guided missons meaning a point is given to fly to. However the exact points are unknown to me.
Here is a graph of a single flight lat/lng shifted to near (0,0) so they are visible on the same time-series graph.
I attempted to generate similar data, but there are several constraints and it may take more time to solve than working on the segmenting.
The graphs start and end nearly always at the same point.
Horisontal lines mean the UAV is stationary. These segments are expected.
Beginning and and end are always stationary for takeoff and landing.
There is some level of noise in the lines for the gps accuracy tho seemingly not that much.
Alot of data points.
The number of segments is unknown.
The noise I could calculate given the segments and least squares method to the line. Currently I'm thinking of sampling the data (to decimate it a little) and constructing lines. Merging the lines with smaller angle than x (dependant on the noise) and finding the intersection points of the lines left.
Another thought is to try and look at this problem in the frequency domain. The corners should be quite high frequency. Maybe I could make a custom filter kernel that would enable me to use a window function and win in efficency.
EDIT: Rewrote the question for more clarity and less rambling.
I have a list of (x, y) points. I know how to make a list of Bézier curves which pass through all of those points and have a continuous first (and second, though less important) derivative. However, the list that I end up with is far too long. I would prefer to approximate the points I have if it lets me cut down on the number of curves I have. I would like to be able to pass a parameter of either how close an approximation I get or a maximum number of curves, preferably the former.
The reason I want this is that the end result will have a graphical UI where users can edit the Bézier curves, and it isn't critical that the curves pass through each point exactly, as long as they are close. More curves makes it harder to edit.
EDIT:
Some more information about the purpose of this. I'm trying to make image editing software. When someone loads a bitmap, I want to be able to trace a center line. Potrace is what I would use to trace the outline of a shape, but it won't work for tracing strokes. I've been able to identify lots of points along the center line, and I want to turn this data into a list of connected Bézier curves. The reason I don't want to make a Bézier spline is that there will be too many control points for this to be easy to edit. "Too many" is not an easy-to-define term, but I would like to be able to pass a parameter to limit the number of curves. Either a function that minimizes how far the curves are from the points based on a maximum number of curves or a function that minimizes the number of curves based on a maximum deviation from the points.
Several approaches exist for achieving what you want to do:
1) Use RDP algorithm to reduce the number of points, then create a list of Bezier curves passing thru the remaining points.
2) Use curve fitting algorithms (for example, Schneider algorithm) to produce multiple Bezier curves that are connected with G1 (tangent) continuity. Check out Schneider algorithm implementation in this link.
3) Use least square fitting with B-spline to produce a single B-spline curve.
From implementation point of view, approach 1 is probably the easiest one for you as you already know how to create Bezier curves interpolating a list of points. Approach 3 will be much more difficult to implement and you probably will have to convert the B-spline curve into Bezier curves so as to use them at the UI level. Please refer to this SO article for detailed discussion.
So I am using Kinect with Unity.
With the Kinect, we detect a hand gesture and when it is active we draw a line on the screen that follows where ever the hand is going. Every update the location is stored as the newest (and last) point in a line. However the lines can often look very choppy.
Here is a general picture that shows what I want to achieve:
With the red being the original line, and the purple being the new smoothed line. If the user suddenly stops and turns direction, we think we want it to not exactly do that but instead have a rapid turn or a loop.
My current solution is using Cubic Bezier, and only using points that are X distance away from each other (with Y points being placed between the two points using Cubic Bezier). However there are two problems with this, amongst others:
1) It often doesn't preserve the curves to the distance outwards the user drew them, for example if the user suddenly stop a line and reverse the direction there is a pretty good chance the line won't extend to point where the user reversed the direction.
2) There is also a chance that the selected "good" point is actually a "bad" random jump point.
So I've thought about other solutions. One including limiting the max angle between points (with 0 degrees being a straight line). However if the point has an angle beyond the limit the math behind lowering the angle while still following the drawn line as best possible seems complicated. But maybe it's not. Either way I'm not sure what to do and looking for help.
Keep in mind this needs to be done in real time as the user is drawing the line.
You can try the Ramer-Douglas-Peucker algorithm to simplify your curve:
https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
It's a simple algorithm, and parameterization is reasonably intuitive. You may use it as a preprocessing step or maybe after one or more other algorithms. In any case it's a good algorithm to have in your toolbox.
Using angles to reject "jump" points may be tricky, as you've seen. One option is to compare the total length of N line segments to the straight-line distance between the extreme end points of that chain of N line segments. You can threshold the ratio of (totalLength/straightLineLength) to identify line segments to be rejected. This would be a quick calculation, and it's easy to understand.
If you want to take line segment lengths and segment-to-segment angles into consideration, you could treat the line segments as vectors and compute the cross product. If you imagine the two vectors as defining a parallelogram, and if knowing the area of the parallegram would be a method to accept/reject a point, then the cross product is another simple and quick calculation.
https://www.math.ucdavis.edu/~daddel/linear_algebra_appl/Applications/Determinant/Determinant/node4.html
If you only have a few dozen points, you could randomly eliminate one point at a time, generate your spline fits, and then calculate the point-to-spline distances for all the original points. Given all those point-to-spline distances you can generate a metric (e.g. mean distance) that you'd like to minimize: the best fit would result from eliminating points (Pn, Pn+k, ...) resulting in a spline fit quality S. This technique wouldn't scale well with more points, but it might be worth a try if you break each chain of line segments into groups of maybe half a dozen segments each.
Although it's overkill for this problem, I'll mention that Euler curves can be good fits to "natural" curves. What's nice about Euler curves is that you can generate an Euler curve fit by two points in space and the tangents at those two points in space. The code gets hairy, but Euler curves (a.k.a. aesthetic curves, if I remember correctly) can generate better and/or more useful fits to natural curves than Bezier nth degree splines.
https://en.wikipedia.org/wiki/Euler_spiral
I am trying to do flight planning in 3D space, but I actually want to figure out doing it in 2D space first. I have:
an object with a known current position and known current velocity vector
a desired point in space
a desired velocity vector
a desired time
I want to plan a route for the object to take to reach the desired point at the desired time travelling at the desired vector, and taking into account the objects starting vector.
I'm at a bit of a loss on how to achieve this. Any help appreciated.
As noted by eigenchris in a comment, this problem has many possible solutions, so I will propose a method that gives sensible results and allows for flexible customization, depending on the desired properties of your path.
It's easier to split the problem into two parts, first find a path in 2D and then compute the distance along it and solve the problem of matching the velocity and acceleration to the distance as a 1D (plus time) problem.
For the path, Cubic Bézier curves seem ideally suited to the problem. A cubic Bézier curve is defined by 4 control points P0, P1, P2 and P3.
P0 and P3 are the start and end points of the curve. P1 and P2 are control points that are used for specifying the tangent of the curve at the start and end points (defined by the lines P0-P1 and P2-P3 respectively). If you fly along the curve, those are the directions you are moving at the start and end points.
Here is an interactive demo to get a feel for how the positioning of the control points influences the curve (the cubic Bézier is the blue curve on the right with 4 control points).
To define a flight path using a Bézier curve:
Set P0 to the start point of your flight path
Set P3 to the end point
Set P1 to a point in the direction of the starting velocity vector from P0
Set P2 to a point in the opposite direction to the ending velocity vector from P3
Note that the distances from P0 to P1 and from P2 to P3 do not represent the magnitude of the starting and ending velocities. Rather, they specify the tightness of the turn at the start and end of the curve to align the curve with the start and end tangents. Pull the control points in close for a tight turn, push them further out for a wider turn. However if you want to you can make the turn wider the larger the desired velocity vector is, to be more physically realistic.
If you don't want to be turning the whole time, you can segment the path into several Bézier curves, or a Bézier curve then a straight line then a Bézier curve, and make the tangents match up where the different segments meet. For example you might want to take a curved path at the start of the flight path, then follow a straight line for most of the way, the follow a curved path at the end to line up with the desired final direction vector. This gives you total control over your flight path.
The solution generalizes easily to 3 dimensions.
Now that you have a path, you need to figure out how to accelerate and decelerate along the curve to arrive at the destination at the right time and the right speed. First, calculate the distance along the curve:
Arc Length of Bézier Curves
If you know the start time, the end time and the start and end speeds (magnitude of start and end velocity vectors), you can work out how far along the curve you would have flown between the start and end times, assuming you linearly accelerate from the starting speed to the ending speed over the course of the journey (distance is the area under the line):
Since this area will most likely be different to the computed distance along the Bézier Curve, you need to create a segmented function that has the desired area under the line between the start and end times. The image shows two such functions to handle the cases where the distance traveled is greater than desired, and the area is decreased by slowing down then travelling at constant speed then speeding up, and vice versa. The examples show instantaneous changes in acceleration, but not in speed. You can choose any function you like as long as the start and end speeds at the start and end times match the desired values and the area under the function is equal to the distance along the path.
I'm writing a data analysis program and part of it requires finding the volume of a shape. The shape information comes in the form of a lost of points, giving the radius and the angular coordinates of the point.
If the data points were uniformly distributed in coordinate space I would be able to perform the integral, but unfortunately the data points are basically randomly distributed.
My inefficient approach would be to find the nearest neighbours to each point and stitch the shape together like that, finding the volume of the stitched together parts.
Does anyone have a better approach to take?
Thanks.
IF those are surface points, one good way to do it would be to discretize the surface as triangles and convert the volume integral to a surface integral using Green's Theorem. Then you can use simple Gauss quadrature over the triangles.
Ok, here it is, along duffymo's lines I think.
First, triangulate the surface, and make sure you have consistent orientation of the triangles. Meaning that orientation of neighbouring triangle is such that the common edge is traversed in opposite directions.
Second, for each triangle ABC compute this expression: H*cross2D(B-A,C-A), where cross2D computes cross product using coordinates X and Y only, ignoring the Z coordinates, and H is the Z-coordinate of any convenient point in the triangle (although the barycentre would improve precision).
Third, sum up all the above expressions. The result would be the signed volume inside the surface (plus or minus depending on the choice of orientation).
Sounds like you want the convex hull of a point cloud. Fortunately, there are efficient ways of getting you there. Check out scipy.spatial.ConvexHull.