Any techniques to draw path animated? - iphone

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).

Related

Draw elliptical arc between 2 points using bezier curve

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:

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);

Randomly drawing from a hypercube in Matlab

Consider the n-cube (defined here) with n>3. Suppose that it centered at the origin of the Cartesian plane and each edge has length 10.
I would like to write a piece of code in Matlab that allows me to randomly draw one point (with n coordinates) from this hypercube. Is there a way to do it without pre-defining a n-dimensional grid? In my particular application n=11.
To draw 1 point from the volume of an n-dimensional hypercube with side s, with all points having equal probability, you call
s = 10;
point = (rand(1,n)-0.5)*s;
Replace the 1 with a larger number if you want to draw many points at once.
Extending Jonas' answer, if you want to specify a center, do this:
center = [1.0 -1.0 2.0 -2.0 ...];
s = 10;
point = (rand(1,n)-0.5)*s + center;

Find Position based on signal strength (intersection area between circles)

I'm trying to estimate a position based on signal strength received from 4 Wi-Fi Access Points. I measure the signal strength from 4 access points located in each corner of a square room with 100 square meters (10x10). I recorded the signal strengths in a known position (x, y) = (9.5, 1.5) using an Android phone. Now I want to check how accurate can a multilateration method be under the circumstances.
Using MATLAB, I applied a formula to calculate distance using the signal strength. The following MATLAB function shows the application of the formula:
function [ d_vect ] = distance( RSS )
% Calculate distance from signal strength
result = (27.55 - (20 * log10(2400)) + abs(RSS)) / 20;
d_vect = power(10, result);
end
The input RSS is a vector with the four signal strengths measured in the test point (x,y) = (9.5, 1.5). The RSS vector looks like this:
RSS =
-57.6000
-60.4000
-44.7000
-54.4000
and the resultant vector with all the estimated distances to each access points looks like this:
d_vect =
7.5386
10.4061
1.7072
5.2154
Now I want to estimate my position based on these distances and the access points position in order to find the error between the estimated position and the known position (9.5, 1.5). I want to find the intersection area (In order to estimate a position) between four circles where each access point is the center of one of the circles and the distance is the radius of the circle.
I want to find the grey area as shown in this image :
http://www.biologycorner.com/resources/venn4.gif
If you want an alternative way of estimating the location without estimating the intersection of circles you can use trilateration. It is a common technique in navigation (e.g. GPS) to estimate a position given a set of distance measurements.
Also, if you wanted the area because you also need an estimate of the uncertainty of the position I would recommend solving the trilateration problem using least squares which will easily give you an estimate of the parameters involved and an error propagation to yield an uncertainty of the location.
I found an answear that solved perfectly the question. It is explained in detail in this link:
https://gis.stackexchange.com/questions/40660/trilateration-algorithm-for-n-amount-of-points
I also developed some MATLAB code for the problem. Here it goes:
Estimate distances from the Access Points:
function [ d_vect ] = distance( RSS )
result = (27.55 - (20 * log10(2400)) + abs(RSS)) / 20;
d_vect = power(10, result);
end
The trilateration function:
function [] = trilat( X, d, real1, real2 )
cla
circles(X(1), X(5), d(1), 'edgecolor', [0 0 0],'facecolor', 'none','linewidth',4); %AP1 - black
circles(X(2), X(6), d(2), 'edgecolor', [0 1 0],'facecolor', 'none','linewidth',4); %AP2 - green
circles(X(3), X(7), d(3), 'edgecolor', [0 1 1],'facecolor', 'none','linewidth',4); %AP3 - cyan
circles(X(4), X(8), d(4), 'edgecolor', [1 1 0],'facecolor', 'none','linewidth',4); %AP4 - yellow
axis([0 10 0 10])
hold on
tbl = table(X, d);
d = d.^2;
weights = d.^(-1);
weights = transpose(weights);
beta0 = [5, 5];
modelfun = #(b,X)(abs(b(1)-X(:,1)).^2+abs(b(2)-X(:,2)).^2).^(1/2);
mdl = fitnlm(tbl,modelfun,beta0, 'Weights', weights);
b = mdl.Coefficients{1:2,{'Estimate'}}
scatter(b(1), b(2), 70, [0 0 1], 'filled')
scatter(real1, real2, 70, [1 0 0], 'filled')
hold off
end
Where,
X: matrix with APs coordinates
d: distance estimation vector
real1: real position x
real2: real position y
If you have three sets of measurements with (x,y) coordinates of location and corresponding signal strength. such as:
m1 = (x1,y1,s1)
m2 = (x2,y2,s2)
m3 = (x3,y3,s3)
Then you can calculate distances between each of the point locations:
d12 = Sqrt((x1 - x2)^2 + (y1 - y2)^2)
d13 = Sqrt((x1 - x3)^2 + (y1 - y3)^2)
d23 = Sqrt((x2 - x3)^2 + (y2 - y3)^2)
Now consider that each signal strength measurement signifies an emitter for that signal, that comes from a location somewhere at a distance. That distance would be a radius from the location where the signal strength was measured, because one would not know at this point the direction from where the signal came from. Also, the weaker the signal... the larger the radius. In other words, the signal strength measurement would be inversely proportional to the radius. The smaller the signal strength the larger the radius, and vice versa. So, calculate the proportional, although not yet accurate, radius's of our three points:
r1 = 1/s1
r2 = 1/s2
r3 = 1/s3
So now, at each point pair, set apart by their distance we can calculate a constant (C) where the radius's from each location will just touch one another. For example, for the point pair 1 & 2:
Ca * r1 + Ca * r2 = d12
... solving for the constant Ca:
Ca = d12 / (r1 + r2)
... and we can do this for the other two pairs, as well.
Cb = d13 / (r1 + r3)
Cc = d23 / (r2 + r3)
All right... select the largest C constant, either Ca, Cb, or Cc. Then, use the parametric equation for a circle to find where the coordinates meet. I will explain.
The parametric equation for a circle is:
x = radius * Cos(theta)
y = radius * Sin(theta)
If Ca was the largest constant found, then you would compare points 1 & 2, such as:
Ca * r1 * Cos(theta1) == Ca * r2 * Cos(theta2) &&
Ca * r1 * Sin(theta1) == Ca * r2 * Sin(theta2)
... iterating theta1 and theta2 from 0 to 360 degrees, for both circles. You might write code like:
for theta1 in 0 ..< 360 {
for theta2 in 0 ..< 360 {
if( abs(Ca*r1*cos(theta1) - Ca*r2*cos(theta2)) < 0.01 && abs(Ca*r1*sin(theta1) - Ca*r2*sin(theta2)) < 0.01 ) {
print("point is: (", Ca*r1*cos(theta1), Ca*r1*sin(theta1),")")
}
}
}
Depending on what your tolerance was for a match, you wouldn't have to do too many iterations around the circumferences of each signal radius to determine an estimate for the location of the signal source.
So basically you need to intersect 4 circles. There can be many approaches to it, and there are two that will generate the exact intersection area.
First approach is to start with one circle, intersect it with the second circle, then intersect the resulting area with the third circle and so on. that is, on each step you know current intersection area, and you intersect it with a new circle. The intersection area will always be a region bounded by circle arcs, so to intersect it with a new circle you walk along the boundary of the area and check whether each bounding arc intersects with a new circle. If it does, then you leave only the part of the arc that lies inside a new circle, remember that you should continue with an arc from a new circle, and continue traversing the boundary until you find the next intersection.
Another approach that seems to result in a worse time complexity, but in your case of 4 circles this will not be important, is to find all the intersection points of two circles and choose only those points that are of interest for you, that is which lie inside all other circles. These points will be the corners of your area, and then it is rather easy to reconstruct the area. After googling a bit, I have even found a live demo of this approach.

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.