Draw elliptical arc between 2 points using bezier curve - matlab

I need a bezier curve to join the end points of 2 arbitrary lines smoothly. The lines are all either perpendicular or parallel. By "smoothly" I mean I want the curve's tangent at the end points to have the same slope as the lines.
I'm going to be using MatLab (Octave actually) to write the xml for an svg. So I need a formula to output the positions of the bezier curve's control points based on the positions of the endpoints.
Any help?

If lines are parallel but shifted, then you cannot draw single arc to connect them smoothly, so cubic Bezier curve (that can have S-form) is more suitable.
Let we have the first endpoint P0 with unit direction vector T0, and second endpoint P3 with unit direction vector T3. Control points of cubic Bezier lie on lines continuations. To make curve smooth, we should choose distance of conttrol points from endpoints. Empirical value is about half of distance between endpoints. Method works also for perpendicular lines.
Dist = Sqrt((P0.X - P3.X)^2 + (P0.Y - P3.Y)^2)
Control1.X = P0.X + T0.X * Dist / 2
Control1.Y = P0.Y + T0.Y * Dist / 2
Control2.X = P3.X - T3.X * Dist / 2 //account for T3 direction here
Control2.Y = P3.Y - T3.Y * Dist / 2
Example of curve generated with described approach:

Related

Finding the tangent on a given point of a polyline

I have a list of X,Y coordinates that represents a road. For every 5 meters, I need to calculate the angle of the tangent on this road, as I have tried to illustrate in the image.
My problem is that this road is not represented by a mathematical function that I can simply derive, it is represented by a list of coordinates (UTM33N).
In my other similar projects we use ArcGIS/ESRI libraries to perform geographical functions such as this, but in this project I need to be independent of any software that require the end user to have a license, so I need to do the calculations myself (or find a free/open source library that can do it).
I am using a cubic spline function to make the line rounded between the coordinates, since all tangents on a line segment would just be parallell to the segment otherwise.
But now I am stuck. I am considering simply calculating the angle between any three points on the line (given enough points), and using this to find the tangents, but that doesn't sound like a good method. Any suggestions?
In the end, I concluded that the points were plentiful enough to give an accurate angle using simple geometry:
//Calculate delta values
var dx = next.X - curr.X;
var dy = next.Y - curr.Y;
var dz = next.Z - curr.Z;
//Calculate horizontal and 3D length of this segment.
var hLength = Math.Sqrt(dx * dx + dy * dy);
var length = Math.Sqrt(hLength * hLength + dz * dz);
//Calculate horizontal and vertical angles.
hAngle = Math.Atan(dy/dx);
vAngle = Math.Atan(dz/hLength);

finding the intersection of a line with a non monotonic arbitrary surface?

I have a surface Z on a X-Y grid for which I want to find the intersection point with a line. I used so far this code for finding the intersection:
x_ray = x_source + t * x_dir
y_ray = y_source + t * y_dir
z_ray = z_source + t * z_dir
height_above_plane = #(t) z_source + t * z_dir - interp2(X, Y, Z, ...
x_source + t*x_dir, y_source + t*y_dir)
t_intercept = fzero(height_above_plane, 0);
my problem is that when my surface is "wiggly", the function has several zero crossing points, and I want to find the minimal out of them.
How can I do that?
Thanks
A possible approach is to project the ray onto the XY domain and draw the corresponding Bresenham line. As you go along this line, grid cell per grid cell, you will compute the Z altitudes along the ray and check if their range overlaps the range of altitudes of the surface (i.e. the min and max value in this cell).
If yes, you have to find the 3D intersection between the ray and the interpolating surface, an hyperbolic paraboloid. If the intersection does fall inside the grid cell considered, you are done. Otherwise, continue the march along the ray.
Convert the surface to matlab mesh, then use this code.

Approximating relative angle between two line segments on sphere surface

I am in need of an idea! I want to model the vascular network on the eye in 3D. I have made statistics on the branching behaviour in relation to vessel diameter, length etc. What I am stuck at right now is the visualization:
The eye is approximated as a sphere E with center in origo C = [0, 0, 0] and a radius r.
What I want to achieve is that based on the following input parameters, it should be able to draw a segment on the surface/perimeter of E:
Input:
Cartesian position of previous segment ending: P_0 = [x_0, y_0, z_0]
Segment length: L
Segment diameter: d
Desired angle relative to the previous segment: a (1)
Output:
Cartesian position of resulting segment ending: P_1 = [x_1, y_1, z_1]
What I do now, is the following:
From P_0, generate a sphere with radius L, representing all the points we could possibly draw to with the correct length. This set is called pool.
Limit pool to only include points with a distance to C between r*0.95 and r, so only the points around the perimeter of the eye are included.
Select only the point that would generate a relative angle (2) closest to the desired angle a.
The problem is, that whatever angle a I desire, is actually not what is measured by the dot product. Say I want an angle at 0 (i.e. that the new segment is following the same direction as the previous`, what I actually get is an angle around 30 degrees because of the curvature of the sphere. I guess what I want is more the 2D angle when looking from an angle orthogonal from the sphere to the branching point. Please take a look at the screenshots below for a visualization.
Any ideas?
(1) The reason for this is, that the child node with the greatest diameter is usually follows the path of the previous segment, whereas smaller child nodes tend to angle differently.
(2) Calculated by acos(dot(v1/norm(v1), v2/norm(v2)))
Screenshots explaining the problem:
Yellow line: previous segment
Red line: "new" segment to one of the points (not neccesarily the correct one)
Blue x'es: Pool (text=angle in radians)
I will restate the problem with my own notation:
Given two points P and Q on the surface of a sphere centered at C with radius r, find a new point T such that the angle of the turn from PQ to QT is A and the length of QT is L.
Because the segments are small in relation to the sphere, we will use a locally-planar approximation of the sphere at the pivot point Q. (If this isn't an okay assumption, you need to be more explicit in your question.)
You can then compute T as follows.
// First compute an aligned orthonormal basis {U,V,W}.
// - {U,V} should be a basis for the plane tangent at Q.
// - W should be normal to the plane tangent at Q.
// - U should be in the direction PQ in the plane tangent at Q
W = normalize(Q - C)
U = normalize(Q - P)
U = normalize(U - W * dotprod(W, U))
V = normalize(crossprod(W, U))
// Next compute the next point S in the plane tangent at Q.
// In a regular plane, the parametric equation of a unit circle
// centered at the origin is:
// f(A) = (cos A, sin A) = (1,0) cos A + (0,1) sin A
// We just do the same thing, but with the {U,V} basis instead
// of the standard basis {(1,0),(0,1)}.
S = Q + L * (U cos A + V sin A)
// Finally project S onto the sphere, obtaining the segment QT.
T = C + r * normalize(S - C)

Incorrect angle detected between two planes

I want to calculate the angle between 2 planes, Reference plane and Plane1. When I feed the X,Y,Z co-ordinates of pointCloud to the function plane_fit.m (by Kevin Mattheus Moerman), I get the coefficients:
reference_plane_coeff: [-0.13766204 -0.070385590 130.69409]
Plane1_coeff: [0.0044337390 -0.0013548643 95.890228]
Next, I find the intersection of both planes, separately on the XZ plane and get a line equation; ref_line_XZ and plane1_line_XZ respectively. For this, I make the second coefficient 0. (Is this right?)
Aref = reference_plane_coeff(1);
Cref = reference_plane_coeff(3);
ref_line_XZ = [Aref Cref];
Arun = Plane1_coeff(1);
Crun = Plane1_coeff(3);
plane1_line_XZ = [Arun Crun];
angle_XZ = acos( dot(ref_line_XZ,plane1_line_XZ ) / (norm(ref_line_XZ) * norm(plane1_line_XZ )) )
I get the angle_XZ value as 0.0012 rad. i.e. 0.0685 degrees
When I plot these planes on a graph and view it, the angle seems to be much more than 0.0012 degrees. I'm talking about the angle made by the two lines after intersection of both planes with the XZ plane.
What am I doing wrong?
Also, when I tried to find angle between its normals, using:
angle_beta_deg = acosd( dot(reference_plane_coeff,Plane1_coeff) / (norm(reference_plane_coeff) * norm(Plane1_coeff)) )
I got the angle as 0.0713.
On visual inspection of both planes' plots and manually calculating from the plot, angle_XZ should be around 9 degrees.
plane_fit.m (by Kevin Mattheus Moerman)

Any techniques to draw path animated?

Is there a way to simulate handwriting using quartz?
I mean there is a path between points A, B and C.
I want path to come out of point A and go animated to point B and then C.
What comes to mind is two options to do it:
Ugly- Create path then mask it and move mask around to reveal a path.
Takes a lot of time to create and unreliable and ugly hack
move points A,B,C and draw line between them.
Some way to animate a circle along a path leaving the trail?
Any techniques, examples?
Thanks.
Make a CAShapeLayer and then animate its path.
As mentioned in the comment above an ideal API would be one that would let you draw any arbitrary segment along the path but I have not seen any such API.
Another approach would be to define your path is discreet segments. Then use NSBezierPath's element methods to walk along the path and draw each segment along the way on a timer or using NSAnimation. The problem with this approach is that is does not let you use any arbitrary path.
A bezier curve defines a way to get a set of points based on an unrelated parameter, usually called t. To render the full curve, you evaluate t between 0 and 1 and draw a line from each point to the next. To render less than the full curve, you evaluate t from 0 to a number less than one. To animate drawing the curve, you could evaluate the points and draw the segments on a timer.
You can split a bezier curve at an arbitrary t. Doing that will allow you to pass the curve to the system to draw, or to use in a CAShapeLayer.
A handwritten letter will usually be a series of bezier curves, or a bezier spline. The end point of one curve is the start point of the next. Think of t as going from zero to the number of segments in the spline. If there are 3 curves, think of t as going from 0 to 3. When t is between 1 and 2, you would pass the whole first segment and part of the second segment to the system to draw.
You can read about DeCasteljau's algorithm for splitting bezier curves. Here is a code sample for a cubic bezier curve on a plane:
// initial curve is four point x0,y0 , x1,y1 , x2,y2 , x3,y3
// x0,y0 and x3,y3 are the anchors
// point to split curve at is 0<t<1
nt = 1.0 - t;
x01 = nt * x0 + t * x1;
y01 = nt * y0 + t * y1;
x12 = nt * x1 + t * x2;
y12 = nt * y1 + t * y2;
x23 = nt * x2 + t * x3;
y23 = nt * y2 + t * y3;
x012 = nt * x01 + t * x12;
y012 = nt * y01 + t * y12;
x123 = nt * x12 + t * x23;
y123 = nt * y12 + t * y23;
x0123 = nt * x012 + t * x123;
y0123 = nt * y012 + t * y123;
// now the new curve you want is
// x0,y0 , x01,y01 , x012,y012 , x0123,y0123
// the other half of the curve, discarded in your case, is
// x0123,y0123 , x123,y123 , x23,y23 , x3,y3
So given a series of curves that describe your handwritten character, you would animate from 0 to T, where T is the number of curves. calculate t=T-floor(T) and when t is not zero, use it to split the curve at n=floor(T).