Apache flex 如何一次从3个给定点绘制连续曲线
我试图用闪光灯画一条连续的曲线。有很多方法,但到目前为止,我发现没有一种方法完全符合我的要求。首先,我想使用flash graphic api的curveTo()方法。我不想。根据我的经验和理解,线段需要大量处理器。闪存的二次贝塞尔曲线应该占用更少的CPU电源。如果你认为我错了,请挑战这个假设 我也不想使用将整行作为参数的预制方法(例如mx.charts.ChartClass.GraphicsUtilities.drawPolyline())。 原因是,我最终需要修改逻辑,以便为我正在绘制的线条添加装饰,因此我需要一些我在最低层次上理解的东西 我目前创建了一个方法,可以在给定3个点的情况下绘制曲线 这是一张照片: 问题是这些线实际上并没有通过线的“真实”点(灰色圆)弯曲。有没有一种方法可以利用数学的力量来调整控制点,使曲线实际通过“真实”点?仅将当前点及其上/下一点作为参数?下面是复制上述图片的代码。如果我能修改它以满足这个要求,那就太好了(注意第一点和最后一点的例外)Apache flex 如何一次从3个给定点绘制连续曲线,apache-flex,actionscript-3,bezier,continuous,spline,Apache Flex,Actionscript 3,Bezier,Continuous,Spline,我试图用闪光灯画一条连续的曲线。有很多方法,但到目前为止,我发现没有一种方法完全符合我的要求。首先,我想使用flash graphic api的curveTo()方法。我不想。根据我的经验和理解,线段需要大量处理器。闪存的二次贝塞尔曲线应该占用更少的CPU电源。如果你认为我错了,请挑战这个假设 我也不想使用将整行作为参数的预制方法(例如mx.charts.ChartClass.GraphicsUtilities.drawPolyline())。 原因是,我最终需要修改逻辑,以便为我正在绘制的线条
包{
导入flash.display.Shape;
导入flash.display.Sprite;
导入flash.display.Stage;
导入flash.geom.Point;
[SWF(width=“200”,height=“200”)]
公共类TestCurves扩展了Sprite{
公共函数TestCurves(){
stage.scaleMode=“noScale”;
变量点:数组=[
新观点(10,10),
新点(80,80),
新点(80160),
新观点(20160),
新点(20200),
新点(200100)
];
图形。线条样式(2,0xFF0000);
变量点:点=点[0];
var nextPoint:Point=points[1];
样条线方法。绘制样条线(图形、点、空、下一点);
var prevPoint:点=点;
变量n:int=points.length;
变量i:int;
对于(i=2;i
稍后,我将向draw方法添加箭头和其他内容。我想您正在寻找Catmull Rom样条线。我已经为您搜索了一个AS3实现,但还没有尝试过,所以请自行决定使用:
好的,Catmull-Rom样条线建议很好,但并不完全是我想要的。 提供的链接中的示例是一个很好的起点,但有点不灵活。我已经使用了它,并修改了我的原始源代码以使用它。我将此作为一个答案发布,因为我认为它比Zevan的博客文章(无意冒犯Zevan!)更模块化,更容易理解。以下代码将显示以下图像: 代码如下:
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="300",height="300")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
//draw a helpful grid
graphics.lineStyle(1, 0xC0C0C0, 0.5);
for (var x:int = 0; x <= 300; x += 10) {
graphics.moveTo(x, 0);
graphics.lineTo(x, 300);
graphics.moveTo(0, x);
graphics.lineTo(300, x);
}
var points:Array = [
new Point(40, 20),
new Point(120, 80),
new Point(120, 160),
new Point(60, 160),
new Point(60, 200),
new Point(240, 150),
new Point(230, 220),
new Point(230, 280)
];
SplineMethod.setResolution(5);
graphics.lineStyle(2, 0xF00000);
graphics.moveTo(points[0].x, points[0].y);
var n:int = points.length;
var i:int;
for (i = 0; i < n - 1; i++) {
SplineMethod.drawSpline(
graphics,
points[i], //segment start
points[i + 1], //segment end
points[i - 1], //previous point (may be null)
points[i + 2] //next point (may be null)
);
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0x808080, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
//default setting will just draw a straight line
private static var hermiteValues:Array = [0, 0, 1, 0];
public static function setResolution(value:int):void {
var resolution:Number = 1 / value;
hermiteValues = [];
for (var t:Number = resolution; t <= 1; t += resolution) {
var h00:Number = (1 + 2 * t) * (1 - t) * (1 - t);
var h10:Number = t * (1 - t) * (1 - t);
var h01:Number = t * t * (3 - 2 * t);
var h11:Number = t * t * (t - 1);
hermiteValues.push(h00, h10, h01, h11);
}
}
public static function drawSpline(target:Graphics, segmentStart:Point, segmentEnd:Point, prevSegmentEnd:Point=null, nextSegmentStart:Point=null):void {
if (!prevSegmentEnd) {
prevSegmentEnd = segmentStart;
}
if (!nextSegmentStart) {
nextSegmentStart = segmentEnd;
}
var m1:Point = new Point((segmentEnd.x - prevSegmentEnd.x) / 2, (segmentEnd.y - prevSegmentEnd.y) / 2);
var m2:Point = new Point((nextSegmentStart.x - segmentStart.x) / 2, (nextSegmentStart.y - segmentStart.y) / 2);
var n:int = hermiteValues.length;
for (var i:int = 0; i < n; i += 4) {
var h00:Number = hermiteValues[i];
var h10:Number = hermiteValues[i + 1];
var h01:Number = hermiteValues[i + 2];
var h11:Number = hermiteValues[i + 3];
var px:Number = h00 * segmentStart.x + h10 * m1.x + h01 * segmentEnd.x + h11 * m2.x;
var py:Number = h00 * segmentStart.y + h10 * m1.y + h01 * segmentEnd.y + h11 * m2.y;
target.lineTo(px, py);
}
}
}
包{
导入flash.display.Shape;
导入flash.display.Sprite;
导入flash.display.Stage;
导入flash.geom.Point;
[SWF(width=“300”,height=“300”)]
公共类TestCurves扩展了Sprite{
公共函数TestCurves(){
stage.scaleMode=“noScale”;
//画一个有用的网格
图形.线条样式(1,0xC0,0.5);
对于(var x:int=0;x我编写了这个代码,我认为它可能会有帮助:
主权财富基金:
代码:
我在代码上留下了很多评论。我希望它能有所帮助
以下是代码背后的理论:
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="300",height="300")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
//draw a helpful grid
graphics.lineStyle(1, 0xC0C0C0, 0.5);
for (var x:int = 0; x <= 300; x += 10) {
graphics.moveTo(x, 0);
graphics.lineTo(x, 300);
graphics.moveTo(0, x);
graphics.lineTo(300, x);
}
var points:Array = [
new Point(40, 20),
new Point(120, 80),
new Point(120, 160),
new Point(60, 160),
new Point(60, 200),
new Point(240, 150),
new Point(230, 220),
new Point(230, 280)
];
SplineMethod.setResolution(5);
graphics.lineStyle(2, 0xF00000);
graphics.moveTo(points[0].x, points[0].y);
var n:int = points.length;
var i:int;
for (i = 0; i < n - 1; i++) {
SplineMethod.drawSpline(
graphics,
points[i], //segment start
points[i + 1], //segment end
points[i - 1], //previous point (may be null)
points[i + 2] //next point (may be null)
);
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0x808080, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
//default setting will just draw a straight line
private static var hermiteValues:Array = [0, 0, 1, 0];
public static function setResolution(value:int):void {
var resolution:Number = 1 / value;
hermiteValues = [];
for (var t:Number = resolution; t <= 1; t += resolution) {
var h00:Number = (1 + 2 * t) * (1 - t) * (1 - t);
var h10:Number = t * (1 - t) * (1 - t);
var h01:Number = t * t * (3 - 2 * t);
var h11:Number = t * t * (t - 1);
hermiteValues.push(h00, h10, h01, h11);
}
}
public static function drawSpline(target:Graphics, segmentStart:Point, segmentEnd:Point, prevSegmentEnd:Point=null, nextSegmentStart:Point=null):void {
if (!prevSegmentEnd) {
prevSegmentEnd = segmentStart;
}
if (!nextSegmentStart) {
nextSegmentStart = segmentEnd;
}
var m1:Point = new Point((segmentEnd.x - prevSegmentEnd.x) / 2, (segmentEnd.y - prevSegmentEnd.y) / 2);
var m2:Point = new Point((nextSegmentStart.x - segmentStart.x) / 2, (nextSegmentStart.y - segmentStart.y) / 2);
var n:int = hermiteValues.length;
for (var i:int = 0; i < n; i += 4) {
var h00:Number = hermiteValues[i];
var h10:Number = hermiteValues[i + 1];
var h01:Number = hermiteValues[i + 2];
var h11:Number = hermiteValues[i + 3];
var px:Number = h00 * segmentStart.x + h10 * m1.x + h01 * segmentEnd.x + h11 * m2.x;
var py:Number = h00 * segmentStart.y + h10 * m1.y + h01 * segmentEnd.y + h11 * m2.y;
target.lineTo(px, py);
}
}
}
A和C是第一个和最后一个点,B是AS3中的“控制点”。您可以这样绘制曲线:
graphics.moveTo(A.x, A.y);
graphics.curveTo(B.x, B.y, C.x, C.y);
现在,D是向量AC的中点,DB的中点是曲线的中点。现在我在代码中做的是将B精确移动到D+DB*2,所以,如果你用该点作为控制点绘制曲线,曲线的中点将是B
PS:对不起,我的英语不好好的,为了得到想要的效果,看起来我在任何给定的时间都可能需要至少4分来使用我的画法。对吗