PHP интерполирует точки на кардинальной кривой - PullRequest
0 голосов
/ 28 августа 2011

У меня есть набор точек x, y и я хочу интерполировать набор более высоких подробных промежуточных точек на кардинальной кривой в php

Я не могу понять, как превратить математическую формулу в Интернете в функцию или класс php

Может ли кто-нибудь помочь?

1 Ответ

3 голосов
/ 29 августа 2011

Вот решение, которое я придумала на случай, если кто-то еще столкнется с той же проблемой

function caculate_cardinal_points($points,$tension=0.5,$steps=20) {

    $return_points = array();
    $tangents = array();

    // calculate tangents
    $previous_point = false;
    for($i=0;$i<count($points);$i++) {
        $px = $points[$i][0];
        $py = $points[$i][1];
        if (isset($points[$i+1]) && isset($points[$i-1])) {
            $tx = ($tension * (($points[$i+1][0]-$px) - ($points[$i-1][0]-$px)));
            $ty = ($tension * (($points[$i+1][1]-$py) - ($points[$i-1][1]-$py))); 
        } elseif (isset($points[$i+1])) {
            $tx = ($tension * (($points[$i+1][0]-$px) - ($points[$i][0]-$px)));
            $ty = ($tension * (($points[$i+1][1]-$py) - ($points[$i][1]-$py)));
        } elseif (isset($points[$i-1])) {
            $tx = ($tension * (($points[$i][0]-$px) - ($points[$i-1][0]-$px)));
            $ty = ($tension * (($points[$i][1]-$py) - ($points[$i-1][1]-$py)));
        }
        $tangents[] = array($tx,$ty);
        $previous_x = $px;
        $previous_y = $py;
    }

    // interpolate
    for($i=0;$i<count($tangents)-1;$i++) {
        $p0x = $points[$i][0];
        $p0y = $points[$i][1];
        $p1x = $points[$i+1][0];
        $p1y = $points[$i+1][1];
        $t0x = $tangents[$i][0];
        $t0y = $tangents[$i][1];
        $t1x = $tangents[$i+1][0];
        $t1y = $tangents[$i+1][1];
        $previous_x = $p0x;
        $previous_y = $p0y;
        $return_points[] = array($p0x,$p0y);
        for ($t=0; $t < $steps; $t++) {
            $s = $t / $steps;    // scale s to go from 0 to 1
            $h1 = 2*pow($s,3) - 3*pow($s,2) + 1;
            $h2 = pow($s,3) - 2*pow($s,2) + $s;
            $h3 = -2*pow($s,3) + 3*pow($s,2);
            $h4 = pow($s,3) - pow($s,2);
            $x = $h1*$p0x+$h2*$t0x+$h3*$p1x+$h4*$t1x;
            $y = $h1*$p0y+$h2*$t0y+$h3*$p1y+$h4*$t1y;
            $return_points[] = array($x,$y);
            $previous_x = $x;
            $previous_y = $y;
        }
        $return_points[] = array($p1x,$p1y);
    }
    return $return_points;
}

Вот пример использования:

<?php

$width =  600;
$height = 600;
$factor = 1;
$steps = 20;
$tension = .25;

$blue = 0x00257ac7;
$green = 0x0096be44;
$black = 0x009999999;
$purple = 0x00b5499a;
$red = 0x00ff5555;
$bgreen = 0x0000ff00;

$img = imagecreatetruecolor( $width*$factor, $height*$factor );

// background fill
imagefill($img, 0, 0, 0x00dddddd);

// some control points
$points = array(
    array(120 *$factor,140 *$factor),
    array(140 *$factor,350*$factor),
    array(180 *$factor,500*$factor),
    array(430*$factor,350*$factor),
    array(390*$factor,210*$factor),
    array(540*$factor,120 *$factor)
);
$last_point = false;
foreach($points as $point) {
    imagefilledellipse($img,$point[0],$point[1],8*$factor,8*$factor,$blue);
    if ($last_point) {
        imageline($img,$point[0],$point[1],$last_point[0],$last_point[1],$purple);
    }
    $last_point = $point;
}


$tangets = array();

// calculate tangents
$previous_point = false;
for($i=0;$i<count($points);$i++) {
    $px = $points[$i][0];
    $py = $points[$i][1];
    if (isset($points[$i+1]) && isset($points[$i-1])) {
        $tx = ($tension * (($points[$i+1][0]-$px) - ($points[$i-1][0]-$px)));
        $ty = ($tension * (($points[$i+1][1]-$py) - ($points[$i-1][1]-$py))); 
    } elseif (isset($points[$i+1])) {
        $tx = ($tension * (($points[$i+1][0]-$px) - ($points[$i][0]-$px)));
        $ty = ($tension * (($points[$i+1][1]-$py) - ($points[$i][1]-$py)));
    } elseif (isset($points[$i-1])) {
        $tx = ($tension * (($points[$i][0]-$px) - ($points[$i-1][0]-$px)));
        $ty = ($tension * (($points[$i][1]-$py) - ($points[$i-1][1]-$py)));
    }
    $tangets[] = array($tx,$ty);
    imageline($img,$px+$tx,$py+$ty,$points[$i][0],$points[$i][1],$black);
    imagefilledellipse($img,$px+$tx,$py+$ty,4*$factor,4*$factor,$green);
    imageline($img,$px-$tx,$py-$ty,$points[$i][0],$points[$i][1],$black);
    imagefilledellipse($img,$px-$tx,$py-$ty,4*$factor,4*$factor,$green);
    $previous_x = $px;
    $previous_y = $py;
}


for($i=0;$i<count($tangets)-1;$i++) {
    $p0x = $points[$i][0];
    $p0y = $points[$i][1];
    $p1x = $points[$i+1][0];
    $p1y = $points[$i+1][1];
    $t0x = $tangets[$i][0];
    $t0y = $tangets[$i][1];
    $t1x = $tangets[$i+1][0];
    $t1y = $tangets[$i+1][1];
    $previous_x = $p0x;
    $previous_y = $p0y;
    for ($t=0; $t < $steps; $t++) {
        $s = $t / $steps;    // scale s to go from 0 to 1
        $h1 = 2*pow($s,3) - 3*pow($s,2) + 1;
        $h2 = pow($s,3) - 2*pow($s,2) + $s;
        $h3 = -2*pow($s,3) + 3*pow($s,2);
        $h4 = pow($s,3) - pow($s,2);
        $x = $h1*$p0x+$h2*$t0x+$h3*$p1x+$h4*$t1x;
        $y = $h1*$p0y+$h2*$t0y+$h3*$p1y+$h4*$t1y;
        //imageline($img,$previous_x,$previous_y,$x,$y,$red);
        $previous_x = $x;
        $previous_y = $y;
    }
    //imageline($img,$previous_x,$previous_y,$p1x,$p1y,$red);
}

$line_points = caculate_cardinal_points($points);
$previous_point = false;
foreach($line_points as $point) {
    if ($previous_point) {
        imageline($img,$previous_point[0],$previous_point[1],$point[0],$point[1],$red);
    }
    $previous_point = $point;
}


$resampled = imagecreatetruecolor( $width, $height);
imagecopyresampled($resampled,$img,0,0,0,0,$width,$height,$width*$factor,$height*$factor);
header( "Content-Type: image/png" );
imagepng($resampled);
imagedestroy($img);
imagedestroy($resampled);
...