views:

639

answers:

4

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:

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

  2. move points A,B,C and draw line between them.

  3. Some way to animate a circle along a path leaving the trail?

Any techniques, examples?

Thanks.

+1  A: 

CoreGraphics is used to to draw static images. Therefore, if you'd like to animate the drawing, I'd say that the least painful way to do it would be to set up an NSTimer that fires 30 times a second or so and progressively draws your path.

Dave DeLong
I don't think this answers the question unless I am mistaken. To clarify my interpretation of the question, they want to define a path and then be able to progressively draw a line along it. You are right that using a timer is likely the way to animate it, the tricky part is how to draw some fraction of a path.Ideally there would be an API that would draw a segment of the path defined by 2 percentages representing the beginning and ending of the segment along the path. Unfortunately I have found no such thing.
Jon Steinmetz
A: 

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.

Jon Steinmetz
There's no `NSBezierPath` on iPhoneOS. (There's `UIBezierPath` but it's *undocumented*.)
KennyTM
Yes, so it is, in that case one could use an array of objects that defined the line from the previous point and then animate along that.
Jon Steinmetz
A: 

Make a CAShapeLayer and then animate its path.

KennyTM
A: 

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

drawnonward