在贝塞尔曲线中添加颜色的算法

Shi*_*ryu 11 php algorithm bezier gd

我正在玩GD库一段时间,特别是Bezier曲线atm.

我使用了一些我修改过的(严重的eval()......).我发现它是GD中使用的通用算法并转换为GD.

现在我想把它带到另一个层面:我想要一些颜色.

线条颜色没有问题,但填充颜​​色更难.

我的问题是:

那有没有适合的算法?我的意思是数学算法或任何已经这样做的语言,以便我可以将它转移到PHP + GD?

EDIT2 所以,我尝试使用更加曲线的@MizardX解决方案:

  • 第一名:50 - 50
  • 最终位置:50 - 200
  • 第一控制点:300 - 225
  • 第二控制点:300 - 25

哪个应该显示:

http://i.stack.imgur.com/vtzE0.png

并给出这个:

http://i.stack.imgur.com/waMkU.png

编辑 我已经阅读了@MizardX解决方案.用imagefilledpolygon它来使它工作.

但它没有按预期工作.请参阅下图以查看问题.顶部图形是我所期望的(现在没有黑线,只有红色部分).

使用的坐标:

  • 第一点是100 - 100
  • 最后一点是300 - 100
  • 第一个控制点是100 - 0
  • 最终控制点是300 - 200

http://i.stack.imgur.com/cWH1y.jpg

底部是我得到的那种算法......

Mar*_*rot 8

将贝塞尔曲线转换为折线/多边形,并填充它.如果以足够近的间隔(~1像素)评估贝塞尔多项式,它将与理想的贝塞尔曲线相同.

我不知道你对Bezier曲线有多熟悉,但这是一个速成课程:

<?php

// Calculate the coordinate of the Bezier curve at $t = 0..1
function Bezier_eval($p1,$p2,$p3,$p4,$t) {
    // lines between successive pairs of points (degree 1)
    $q1  = array((1-$t) * $p1[0] + $t * $p2[0],(1-$t) * $p1[1] + $t * $p2[1]);
    $q2  = array((1-$t) * $p2[0] + $t * $p3[0],(1-$t) * $p2[1] + $t * $p3[1]);
    $q3  = array((1-$t) * $p3[0] + $t * $p4[0],(1-$t) * $p3[1] + $t * $p4[1]);
    // curves between successive pairs of lines. (degree 2)
    $r1  = array((1-$t) * $q1[0] + $t * $q2[0],(1-$t) * $q1[1] + $t * $q2[1]);
    $r2  = array((1-$t) * $q2[0] + $t * $q3[0],(1-$t) * $q2[1] + $t * $q3[1]);
    // final curve between the two 2-degree curves. (degree 3)
    return array((1-$t) * $r1[0] + $t * $r2[0],(1-$t) * $r1[1] + $t * $r2[1]);
}

// Calculate the squared distance between two points
function Point_distance2($p1,$p2) {
    $dx = $p2[0] - $p1[0];
    $dy = $p2[1] - $p1[1];
    return $dx * $dx + $dy * $dy;
}

// Convert the curve to a polyline
function Bezier_convert($p1,$p2,$p3,$p4,$tolerance) {
    $t1 = 0.0;
    $prev = $p1;
    $t2 = 0.1;
    $tol2 = $tolerance * $tolerance;
    $result []= $prev[0];
    $result []= $prev[1];
    while ($t1 < 1.0) {
        if ($t2 > 1.0) {
            $t2 = 1.0;
        }
        $next = Bezier_eval($p1,$p2,$p3,$p4,$t2);
        $dist = Point_distance2($prev,$next);
        while ($dist > $tol2) {
            // Halve the distance until small enough
            $t2 = $t1 + ($t2 - $t1) * 0.5;
            $next = Bezier_eval($p1,$p2,$p3,$p4,$t2);
            $dist = Point_distance2($prev,$next);
        }
        // the image*polygon functions expect a flattened array of coordiantes
        $result []= $next[0];
        $result []= $next[1];
        $t1 = $t2;
        $prev = $next;
        $t2 = $t1 + 0.1;
    }
    return $result;
}

// Draw a Bezier curve on an image
function Bezier_drawfilled($image,$p1,$p2,$p3,$p4,$color) {
    $polygon = Bezier_convert($p1,$p2,$p3,$p4,1.0);
    imagefilledpolygon($image,$polygon,count($polygon)/2,$color);
}

?>
Run Code Online (Sandbox Code Playgroud)

编辑:

我忘了测试这个例程.确实如你所说; 它没有给出正确的结果.现在我修复了两个错误:

  1. 我无意中重用了变量名$p1$p2.我给他们改名$prev$next.
  2. 错误的签到while-loop.现在它循环直到距离足够小,而不是足够大.

  • 您可以减小初始步长,但这只会改变错误的域.解决这个问题的另一种方法是使用细分:http://www.antigrain.com/research/adaptive_bezier/index.html (2认同)