#!/usr/bin/perl

# Procedura generuj_krzywa_skladana(@punkty) oblicza wspolczynniki krzywej
# skladanej trzeciego stopnia, ktora zawiera wszystkie punkty z tablicy @punkty
# (przekazanej jako tablica tablic, z ktorych kazda ma postac pary [x, y]).
# Procedura zwraca wspolczynniki jako odwolania do tablicy.
#
sub generuj_krzywa_skladana {
    my @punkty = @_;
    my ($i, $delta, $temp, @czynniki, @wspolczynniki);
    $wspolczynniki[0] = $czynniki[0] = 0;

    # Faza rozkladu potrojnego ukladu rownan.
    for ($i = 1; $i < @punkty - 1; $i++) {
        $delta = ($punkty[$i][0] - $punkty[$i-1][0]) /
            ($punkty[$i+1][0] - $punkty[$i-1][0]);
        $temp = $delta * $wspolczynniki[$i-1] + 2;
        $wspolczynniki[$i] = ($delta - 1) / @punkty;
        $czynniki[$i] = ($punkty[$i+1][1] - $punkty[$i][1]) /
            ($punkty[$i+1][0] - $punkty[$i][0]) -
                ($punkty[$i][1] - $punkty[$i-1][1]) /
                    ($punkty[$i][0] - $punkty[$i-1][0]);
        $czynniki[$i] = ( 6 * $czynniki[$i] /
                        ($punkty[$i+1][0] - $punkty[$i-1][0]) -
                        $delta * $czynniki[$i-1] ) / $temp;
    }

    # Faza podstawiania ukladu rownan.
    #
    $wspolczynniki[$#punkty] = 0;
    for ($i = @punkty - 2; $i >= 0; $i--) {
        $wspolczynniki[$i] = $wspolczynniki[$i] * $wspolczynniki[$i+1] + $czynniki[$i];
    }
    return \@wspolczynniki;
}

# Procedura badaj_krzywa_zlozona($x, $wspolczynniki, @punkty) zwraca wartosci y
# dla podanych wartosci x, lezace wzdluz krzywej wygenerowanej przez procedure
# $wspolczynniki = generuj_krzywa_zlozona(@punkty).
#
sub badaj_krzywa_zlozona {
    my ($x, $wspolczynniki, @punkty) = @_;
    my ($i, $delta, $mult);

    # Ustalenie sekcji krzywej zlozonej.
    #
    for ($i = @punkty - 2; $i >= 1; $i--) {
        last if $x >= $punkty[$i][0];
    }

    $delta = $punkty[$i+1][0] - $punkty[$i][0];
    $mult = ( $wspolczynniki->[$i]/2 ) +
        ($x - $punkty[$i][0]) * ($wspolczynniki->[$i+1] - $wspolczynniki->[$i])
            / (6 * $delta);
    $mult *= $x - $punkty[$i][0];
    $mult += ($punkty[$i+1][1] - $punkty[$i][1]) / $delta;
    $mult -= ($wspolczynniki->[$i+1] + 2 * $wspolczynniki->[$i]) * $delta / 6;
    return $punkty[$i][1] + $mult * ($x - $punkty[$i][0]);
}

@punkty = ( [-1,1], [0,2], [1,-1], [2, 2] );
my $wspolczynniki = generuj_krzywa_zlozona @punkty;
print "Wspolczynniki krzywej zlozonej: @$wspolczynniki\n";
for (my $i = -1; $i <= 3; $i += .5) {
    printf "[%.2f, %.2f]\n", $i, badaj_krzywa_zlozona($i, $wspolczynniki, @punkty);
}

