I have an Array of Points (CGPoints) which form a curve, actually not a real curve but short line-segments. I need a parallel offset of that curve. Just moving the curve down obviously results in thinner segments if the slope is steep. Any ideas on how i could approach this?
You will need to compute the tangent/normal per segment and then translate the points along the normal.
For a polyline - the normal at a vertex is some combination ((n1 + n2) / 2?) of the two segment normals it straddles, so you may need to take that into account during your "offset" curve computation.
Actually - all you need is the Normal - as indicated here.
Hope this helps.
Related
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!
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 struggle with the orientation of an object I am moving along a hermite curve.
I figured out how to move it at constant speed at also have the tangent of my curve, which would be the forward vector of the moving object. My problem is: How do I know the up and right vector? The easiest way would be to start at a given rotation and then step through the curve always taking the last rotation as a reference for the next one, like in this reference:
Camera movement along a splinepdf
But this would result in an uncontrollable rotation at the end of the spline. What I am trying to do is to create an algorithm which gives you the correct orientation at any point of the curve, without stepping through it. Ideally it would use the orientation of the two controlpoints for the current segment as a reference.
I thought of using some kind of pre-calculated data, which is created from the two orientations of the controlpoints and the current curve segments form, but didn't manage to come up with a solution.
I would be happy to get any answers or just ideas how to approach this problem.
Let C(t) be the camera trajectory, with tangent vector T(t). The tangent vector controls the pitch and the yaw. What you are missing is roll control.
Define an auxiliary trajectory D(t) that "parallels" C(t) and use the vector CD(t). The up vector is given by U(t)=T(t) /\ CD(t) (normalized), and the right vector by U(t) /\ T(t) (normalized).
OK i came up with a solution using frenet frames. I define an orientation for each of my control points, then i calculate a number of points along the spline for each segment. Each points orientation is then calculated using the previous points orientation. The orientatin of the first point equals the orientation of the control point.
Here is a very nice description of the procedure.
After calculating each points orientation, you can interpolate them so the last points orientation matches the orientation of the next controlpoint.
Given an arbitrary sequence of points in space, how would you produce a smooth continuous interpolation between them?
2D and 3D solutions are welcome. Solutions that produce a list of points at arbitrary granularity and solutions that produce control points for bezier curves are also appreciated.
Also, it would be cool to see an iterative solution that could approximate early sections of the curve as it received the points, so you could draw with it.
The Catmull-Rom spline is guaranteed to pass through all the control points. I find this to be handier than trying to adjust intermediate control points for other types of splines.
This PDF by Christopher Twigg has a nice brief introduction to the mathematics of the spline. The best summary sentence is:
Catmull-Rom splines have C1
continuity, local control, and
interpolation, but do not lie within
the convex hull of their control
points.
Said another way, if the points indicate a sharp bend to the right, the spline will bank left before turning to the right (there's an example picture in that document). The tightness of those turns in controllable, in this case using his tau parameter in the example matrix.
Here is another example with some downloadable DirectX code.
One way is Lagrange polynominal, which is a method for producing a polynominal which will go through all given data points.
During my first year at university, I wrote a little tool to do this in 2D, and you can find it on this page, it is called Lagrange solver. Wikipedia's page also has a sample implementation.
How it works is thus: you have a n-order polynominal, p(x), where n is the number of points you have. It has the form a_n x^n + a_(n-1) x^(n-1) + ...+ a_0, where _ is subscript, ^ is power. You then turn this into a set of simultaneous equations:
p(x_1) = y_1
p(x_2) = y_2
...
p(x_n) = y_n
You convert the above into a augmented matrix, and solve for the coefficients a_0 ... a_n. Then you have a polynomial which goes through all the points, and you can now interpolate between the points.
Note however, this may not suit your purpose as it offers no way to adjust the curvature etc - you are stuck with a single solution that can not be changed.
You should take a look at B-splines. Their advantage over Bezier curves is that each part is only dependent on local points. So moving a point has no effect on parts of the curve that are far away, where "far away" is determined by a parameter of the spline.
The problem with the Langrange polynomial is that adding a point can have extreme effects on seemingly arbitrary parts of the curve; there's no "localness" like described above.
Have you looked at the Unix spline command? Can that be coerced into doing what you want?
There are several algorithms for interpolating (and exrapolating) between an aribtrary (but final) set of points. You should check out numerical recipes, they also include C++ implementations of those algorithms.
Unfortunately the Lagrange or other forms of polynomial interpolation will not work on an arbitrary set of points. They only work on a set where in one dimension e.g. x
xi < xi+1
For an arbitary set of points, e.g. an aeroplane flight path, where each point is a (longitude, latitude) pair, you will be better off simply modelling the aeroplane's journey with current longitude & latitude and velocity. By adjusting the rate at which the aeroplane can turn (its angular velocity) depending on how close it is to the next waypoint, you can achieve a smooth curve.
The resulting curve would not be mathematically significant nor give you bezier control points. However the algorithm would be computationally simple regardless of the number of waypoints and could produce an interpolated list of points at arbitrary granularity. It would also not require you provide the complete set of points up front, you could simply add waypoints to the end of the set as required.
I came up with the same problem and implemented it with some friends the other day. I like to share the example project on github.
https://github.com/johnjohndoe/PathInterpolation
Feel free to fork it.
Google "orthogonal regression".
Whereas least-squares techniques try to minimize vertical distance between the fit line and each f(x), orthogonal regression minimizes the perpendicular distances.
Addendum
In the presence of noisy data, the venerable RANSAC algorithm is worth checking out too.
In the 3D graphics world, NURBS are popular. Further info is easily googled.