我正在跟踪鼠标移动以获取一组点来绘制路径。据我所知,我需要使用该点集进行B样条路径。然后,我应该将其缩减为立方贝塞尔曲线(添加到路径的“钢笔工具”功能)。
我已经开发了钢笔工具,使用算法将立方贝塞尔曲线缩减为二次贝塞尔曲线(然后使用Flash curveTo函数)。但我不知道如何创建B样条(或其他简化),然后将其缩减为贝塞尔曲线。
你知道实现这一点的任何方法吗?
jhotdraw 是一个用Java编写的开源绘图项目。它将手绘图形转换为立方贝塞尔曲线。源代码可供下载和翻译。不要被项目的规模吓到:你只需要用到其中的几个类,包括:
org.jhotdraw.geom.Bezier
org.jhotdraw.geom.BezierPath
org.jhotdraw.geom.Geom
在翻译时,将所有集合声明更改为数组(如果仅针对FP10用户,则使用向量)。我有一些正则表达式,你可能会发现在转换中很有用-如果您想要,我可以发布它们。
以下是一些可能有用的正则表达式列表。在每个匹配对中,将第一个粘贴到搜索文本区域中,将第二个粘贴到替换区域中,勾选正则表达式复选框,并使用查找和替换按钮。不要使用Replace All
- 这些都不保证是百分百可靠的。
将所有int/double name
声明替换为var name:Number
\b(double|int)\s+(\w+)\b
var $2:Number
将所有的Point2D.Double name
声明替换为var name:Point
\bPoint2D\.Double\s+(\w+)\b
var $1:Point
将所有函数签名中的 int/double name
声明替换为 name:Number
\(([^)]*)\b(?:double|int)\s+(\w+)\b([^)]*?)\)
($1$2:Number$3)
将所有函数签名中的Point2D.Double name
声明替换为name:Point
\(([^)]*)\b(?:Point2D\.Double)\s+(\w+)\b([^)]*?)\)
($1$2:Point$3)
在更改方法签名之前,请确保所有方法都是静态的:
(public|private)\s+(?!static)
将方法签名替换为AS格式
(public|private)\s+static\s+(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 static function $3($4):$2
使用 array[index] 替换 ArrayList.get(index) //警告:对于 list.get(list.size() - 1) 不适用
(\w+)\.get\(([^)]+)\)
$1[$2]
//avoid the () failure
(\w+)\.get\(([^)]*(?:\([^)]*\))[^)]*)\)
$1[$2]
将ArrayList.set(index, element)
替换为array[index] = element
//警告:对于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]
将arraylist.add(object)
替换为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)
将方法签名替换为AS格式(非静态方法)
(public|private)\s+(?!function)(\w+)\s+(\w+)\s*\(([^)]*)\)
$1 function $3($4):$2
将函数签名中所有的int/double/point/boolean name
声明替换为name:type
\(([^)]*)\b(\w+)\s+(\w+)\b([^)]*?)\)
($1$3:$2$4)
^(\s+)(\w+)\s+(\w+)\s*=\s*(.+?)\s*;(\s*)$
$1var $3:$2 = $4;$5
更改大括号的位置。
^(\t)(\s*)([^\n]+)\{\s*(\n)\s+
$1$2$3$4$1$2{$4$1$2
将 } else
改为 } \n else
^([ \t]+)}[ \t]*else\b([^\n]*)(\n)
$1}$3$1else$2$3
将单行中的4个变量声明拆分成不同行的AS语句
^(\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
更改数组声明
^(\s+)\w+\[\]\s*(\w+)\b
$1 var $2:Array
移除()转换-因为AS编译器不喜欢它们
(?:\(\w+\)\s*)([^ ,*+;/)><=\-])
$1
将max等替换为Math.max - 因为AS不支持静态导入
(?<!Math\.)\b(max|min|abs|sqrt|PI|cos|sin|atan2)\(
Math.$1(
我曾经使用过这个函数一次。
public function multicurve(g: Graphics, args: Array, closed: Boolean): void {
var mid: Array = args.slice(); //制作副本
var i: uint;
var point: Point;
var nextPoint: Point;
var numPoints: uint = mid.length;
if (numPoints == 2) {
g.moveTo(mid[0].x, mid[0].y);
g.lineTo(mid[1].x, mid[1].y);
return;
}
var Xpoint: Array = new Array();
var Ypoint: Array = new Array();
for (i = 1; i < numPoints - 2; i++) {
point = mid[i];
nextPoint = mid[i + 1];
Xpoint[i] = 0.5 * (nextPoint.x + point.x);
Ypoint[i] = 0.5 * (nextPoint.y + point.y);
}
if (closed) {
Xpoint[0] = 0.5 * (mid[1].x + mid[0].x);
Ypoint[0] = 0.5 * (mid[1].y + mid[0].y);
Xpoint[i] = 0.5 * (mid[i + 1].x + mid[i].x);
Ypoint[i] = 0.5 * (mid[i + 1].y + mid[i].y);
Xpoint[i + 1] = 0.5 * (mid[i + 1].x + mid[0].x);
Ypoint[i + 1] = 0.5 * (mid[i + 1].y + mid[0].y);
mid.push(new Point(mid[0].x, mid[0].y));
Xpoint[i + 2] = Xpoint[0];
Ypoint[i + 2] = Ypoint[0];
} else {
Xpoint[0] = mid[0].x;
Ypoint[0] = mid[0].y;
Xpoint[i] = mid[i + 1].x;
Ypoint[i] = mid[i + 1].y;
mid.pop();
numPoints--;
}
g.moveTo(Xpoint[0], Ypoint[0]);
for (i = 1; i < numPoints; i++) {
point = mid[i];
g.curveTo(point.x, point.y, Xpoint[i], Ypoint[i]);
}
if (closed) {
g.curveTo(mid[0].x, mid[0].y, Xpoint[i], Ypoint[i]);
}
}
在C库中有一个算法可以实现您的要求: http://tog.acm.org/resources/GraphicsGems/gems/FitCurves.c
这是一个相当复杂的算法,通过将许多点的列表转换为一些紧密拟合的贝塞尔曲线的列表来简化您的几何图形,从而将涂鸦变成非常平滑的曲线。它具有可调节的松弛度,并通过找到适合您一定松弛度内点集的最少数量的贝塞尔曲线来工作。因此,您设置算法的松弛度越高,您的书写就越平滑(但可能不太准确)。
不确定您是否特别需要贝塞尔曲线,但这个Catmull-Rom样条工具非常棒: http://www.motiondraw.com/md/as_samples/t/CatmullRomSpline/tween.html