Making a smooth path from an irregular number of x,y points to simulate handwriting
actionscript-3, bezier, flash, math
Solution
The jhotdraw is an opensource project in Java for drawing. It converts free hand drawings into cubic bezier curves. The source is available - download and translate. Don't get scared at the size of the project : you need only a couple of classes namely:
org.jhotdraw.geom.Bezier
org.jhotdraw.geom.BezierPath
org.jhotdraw.geom.Geom
While translating start by changing all the collection declarations to Arrays (use vectors if you are targeting only FP10 users). I've some regexes that you might find useful in the conversion - I can post them if you want.
Here is a list of regexes that you might find useful. In each pair, paste the first one into search text area and second one into replace area, check the regex check box and use Find and Replace buttons. Don't use `Replace All` - none of these are guaranteed to be foolproof.
Replace all `int/double name` declarations with `var name:Number`
\b(double|int)\s+(\w+)\b
var $2:Number
Replace all `Point2D.Double name` declarations with `var name:Point`
\bPoint2D\.Double\s+(\w+)\b
var $1:Point
Replace all `int/double name` declarations in function signatures with `name:Number`
\(([^)]*)\b(?:double|int)\s+(\w+)\b([^)]*?)\)
($1$2:Number$3)
Replace all `Point2D.Double name` declarations in function signatures with `name:Point`
\(([^)]*)\b(?:Point2D\.Double)\s+(\w+)\b([^)]*?)\)
($1$2:Point$3)
Before changing method signatures, make sure all methods are static:
(public|private)\s+(?!static)
Replace method signatures to AS format
(public|private)\s+static\s+(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 static function $3($4):$2
Replace ArrayList.get(index) with array[index] //Warning: fails for list.get(list.size() - 1)
(\w+)\.get\(([^)]+)\)
$1[$2]
//avoid the () failure
(\w+)\.get\(([^)]*(?:\([^)]*\))[^)]*)\)
$1[$2]
Replace `ArrayList.set(index, element)` with `array[index] = element` //Warning: fails for list.set(i, list.size())
(\w+)\.set\(([^,]+)\s*,\s*([^)]+)\)
$1[$2] = $3
/*the above regex successfully made the following replacement*/
cleaned.set(cleaned.size() - 1, digitizedPoints[digitizedPoints.size() - 1])
cleaned[cleaned.size() - 1] = digitizedPoints[digitizedPoints.size() - 1]
Replace `arraylist.add(object)` with `array.push(object)`
//would fail if object contains ')'
//add(index, object) should be done with splice
(\w+)\.add\(([^)]+)\)
$1.push($2)
//too many failures - fail safe version -
//still fails for nested parenthesis list.add(new Point(a.first(), a.last()))
//- only three such cases - the effort to match parenthesis wouldn't be worth it
//works for list.add(new Point(3, 4)) - there were many similar cases
(\w+)\.add\(([^)]*(?:\([^)]*\))[^)]*)\)
$1.push($2)
Replace method signatures to AS format (non static methods)
(public|private)\s+(?!function)(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 function $3($4):$2
Replace all `int/double/point/boolean name` declarations in function signatures with `name:type`
\(([^)]*)\b(\w+)\s+(\w+)\b([^)]*?)\)
($1$3:$2$4)
Replace all variable declarations in its own line with an = to AS format
^(\s+)(\w+)\s+(\w+)\s*=\s*(.+?)\s*;(\s*)$
$1var $3:$2 = $4;$5
change placing of braces.
^(\t)(\s*)([^\n]+)\{\s*(\n)\s+
$1$2$3$4$1$2{$4$1$2
change `} else` into `} \n else`
^([ \t]+)}[ \t]*else\b([^\n]*)(\n)
$1}$3$1else$2$3
Replace 4 variable declarations in a single line to AS in different lines
^(\t+)(\w+)\s+(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*;[ \t]*(\n)
$1var $3:$2;$7$1var $4:$2;$7$1var $5:$2;$7$1var $6:$2;$7
Replace array declarations
^(\s+)\w+\[\]\s*(\w+)\b
$1 var $2:Array
Remove () casting - AS compiler doesn't like them
(?:\(\w+\)\s*)([^ ,*+;/)><=\-])
$1
Replace max etc into Math.max - AS doesn't have static imports
(?<!Math\.)\b(max|min|abs|sqrt|PI|cos|sin|atan2)\(
Math.$1(
Problem
I am trying to make a 'brush' tool in AS3 (pure, not Flex) which simulates handwriting, making strokes to be smooth instead of cornered. Then, the trace must be reduced to cubic bezier curves which can be dragged and deformed, affecting the previously drawn path (like the illustrator's pen tool). I'm tracking the mouse movement to get a set of points to draw the path. As far as I know, I need to do a B-Spline path using that set of points. Then I should reduce it to cubic bezier curves (adding the the 'pen tool' functionality to the path). I have already developed the pen tool, using an algorithm which reduces Cubic Beziers to Quadratic Beziers (and then using the Flash curveTo function). But I have no idea how to create a B-Spline (or another simplification), an then reduce it to Bezier curves. Do you know any way to accomplish this?