PHP+GD Интерполяция графика по точкам многочленом Лагранжа

12
A
На сайте с 12.04.2007
Offline
9
2412

Сначала мне казалось, что таким методом можно красиво сгладить любой график. Но моё предположение оказалось ошибочным. Красиво сглаживаются только некоторые функции. А на несвязанных между собой x и y метод вообще говоря может возвращать неясно что. Реализовано, для положительных целых иксов и положительных игреков. Может быть в предверии сессии кому и пригодиться. 100% качества не гарантирую, но вообще оно работает.

Пример работы для заданных иксов 1,2,3,5,8,14,15,16,18,20,22,25 для функции 16/x:

Сам PHP код:

<?php


function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 1)
{
/* this way it works well only for orthogonal lines
imagesetthickness($image, $thick);
return imageline($image, $x1, $y1, $x2, $y2, $color);
*/
if ($thick == 1) {
return imageline($image, $x1, $y1, $x2, $y2, $color);
}
$t = $thick / 2 - 0.5;
if ($x1 == $x2 || $y1 == $y2) {
return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
}
$k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
$a = $t / sqrt(1 + pow($k, 2));
$points = array(
round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
);
imagefilledpolygon($image, $points, 4, $color);
return imagepolygon($image, $points, 4, $color);
}

//Вычисления l_j
function l_j($xp,$i,$x)
{
$n=count($x);
$Chesl = 1.0;
$Znam = 1.0;

for ($k = 0; $k!= $n; $k++ )
{
if ( $k == $i ) continue;
$Chesl *= $xp - $x[$k];
}

for($k= 0; $k!= $n;$k++)
{
if ($x[$i] == $x[$k]) continue;
$Znam *= $x[$i] - $x[$k];
}
return (1.0*$Chesl)/(1.0*$Znam);
}


function Lagranj($x,$xArray,$yArray)
{

if (count ($xArray)!==count($yArray)) return false;
$n=count($xArray);

$result=0;
//Вычисление многочлена Лагранжа
for ($i=0;$i<$n;$i++) $result+=$yArray[$i]*l_j($x,$i,$xArray);
return $result;



}



header("Content-type: image/png");
$imageX=800;
$imageY=500;

$im = @imagecreate($imageX,$imageY)
or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
$grey = imagecolorallocate($im, 200, 200,200);

$text_color = imagecolorallocate($im, 233, 14, 91);
imagelinethick($im,0,$imageY-1,$imageX,$imageY-1,$black,1);
imagelinethick($im,0,0,0,$imageY-1,$black,1);


//Массивы иксов и игреков
$xArray=Array(1,2,3,5,8,14,15,16,18,20,22,25);
$yArray=Array(16,8,5.3333,3.2,2,1.1428,1.0666,1,0.888888,0.8,0.727272,0.64);

$dotes=Array();

$maxX=$xArray[0];
$maxY=$yArray[0];
$minX=$xArray[0];
$minY=$yArray[0];
foreach ($xArray as $vl)
{

if ($maxX<$vl) $maxX=$vl;
if ($minX>$vl) $minX=$vl;

}

$kX=(1.0*$imageX)/(1.0*($maxX-$minX));

$j=0;
for ($i=$minX;$i<=$maxX;$i++)
{
$dotes[$j]=Array("x"=>$i,"y"=>Lagranj($i,$xArray,$yArray));

if (array_search($i,$xArray)===false)
{
array_push($xArray, $i);
array_push($yArray, $dotes[$j]['y']);
}
$j++;

}
foreach ($yArray as $vl)
{
if ($maxY<$vl) $maxY=$vl;
if ($minY>$vl) $minY=$vl;
}
$kY=(1.0*$imageY)/(1.0*($maxY-$minY));

for ($i=$kX;$i<=$imageX;$i+=$kX)
{
imagelinethick($im,0+$i,0,0+$i,$imageY-2,$grey);
}

for ($i=$kY;$i<=$imageY;$i+=$kY)
imagelinethick($im,0+1,$imageY-$i,$imageX,$imageY-$i,$grey);

for ($i=0;$i<count($dotes)-1;$i++) imagelinethick($im,$dotes[$i]["x"]*$kX-$minX*$kX,$imageY-$dotes[$i]["y"]*$kY+$minY*$kY,$dotes[$i+1]["x"]*$kX-$minX*$kX,$imageY-$dotes[$i+1]["y"]*$kY+$minY*$kY,$black);

imagepng($im);
imagedestroy($im);
?>
seo.adman.com: покупка/продажа ссылок, рекламный брокер (http://seo.adman.com) vads.adman.com: свой рекламный брокер за 5 минут (http://vads.adman.com)
verhmax
На сайте с 01.12.2005
Offline
191
#1

молодца! может пригодится кому

stealthy
На сайте с 15.06.2006
Offline
69
#2

Вообще, было бы неплохо для начала вывести интерполируемые значения в виде точек, а уже потом поверх них рисовать интерполированную кривую (ломаную).

Также, поскольку это детская задачка, было бы интересно увидеть не тривиальный код, а хотя бы какую-то творческую деятельность. Например оптимизацию по скорости работы, либо корректную отработку граничных условий. А то сильно напрягает горб в конце, которого быть не должно. А еще было интересно сделать интерполированный график сглаженной линией, а не ломаной однопиксельной ужасного вида. На графике должны быть числовые значения по осям координат. Ну и так далее.

А так... Обычный кусок обычного PHP кода. Только стиль кодирования - плохой. Неаккуратно работаете с отступами, абы как называете переменные (за $Chesl убить мало). Комментарии - русские и английские и отстутствие пробелов после , и ; во второй и далее процедурах наводят на мысли что автором первой процедуры вы не являетесь.

Twilight CMS (http://www.twl.ru): есть Free версия, очень проста и удобна в использовании. Консультирую по любым вопросам. Новый спорт - практическая стрельба (http://nikit.in) - не для офисного планктона.
T
На сайте с 23.10.2005
Offline
60
#3
adman:
на несвязанных между собой x и y метод вообще говоря может возвращать неясно что

ПАТАМУЧТА ЭТА НЕ ФУНКЦИЯ! турист ;)

K
На сайте с 12.07.2006
Offline
295
Kpd
#4
adman:
Сначала мне казалось, что таким методом можно красиво сгладить любой график.

При большом количестве точек добиться сглаживания многочленом Лагранжа нереально, потому что получается многочлен степени n-1. Обычно для сглаживания используют аппроксимацию. Где-то валяется код аппроксимации наименьшими квадрата алгебраическим многочленом заданной степени на делфях, если будет настроение на днях перепишу на php

A
На сайте с 12.04.2007
Offline
9
#5
stealthy:
Вообще, было бы неплохо для начала вывести интерполируемые значения в виде точек, а уже потом поверх них рисовать интерполированную кривую (ломаную).

Также, поскольку это детская задачка, было бы интересно увидеть не тривиальный код, а хотя бы какую-то творческую деятельность. Например оптимизацию по скорости работы, либо корректную отработку граничных условий. А то сильно напрягает горб в конце, которого быть не должно. А еще было интересно сделать интерполированный график сглаженной линией, а не ломаной однопиксельной ужасного вида. На графике должны быть числовые значения по осям координат. Ну и так далее.

А так... Обычный кусок обычного PHP кода. Только стиль кодирования - плохой. Неаккуратно работаете с отступами, абы как называете переменные (за $Chesl убить мало). Комментарии - русские и английские и отстутствие пробелов после , и ; во второй и далее процедурах наводят на мысли что автором первой процедуры вы не являетесь.

Я не утверждал, что код вылизан и причесан. Я ставил перед собой другую задачу и не смог её решить данным методом, однако посчитал, что мой код может быть кому-то полезен. Первую функцию действительно делал не я, она из справки по PHP.

A
На сайте с 12.04.2007
Offline
9
#6
topol:
ПАТАМУЧТА ЭТА НЕ ФУНКЦИЯ! турист ;)

Потому и не ясно, что получится ;)

Kolyaj
На сайте с 28.03.2006
Offline
69
#7
topol:
ПАТАМУЧТА ЭТА НЕ ФУНКЦИЯ! турист

Вы имеете в виду, что набор точек не функция? Хм. А что по-вашему функция? Вот это


-1, если x < 0
f(x) = 0, если x - четно
1, если x - нечетно

по-вашему функция?
T
На сайте с 23.10.2005
Offline
60
#8
Kolyaj:
что по-вашему функция?

загляните в справочник или сходите в школу.

Kolyaj
На сайте с 28.03.2006
Offline
69
#9
topol:
загляните в справочник или сходите в школу.

Ну зачем же. Вышку по математике отпахал уже, хватит.


Определение. Пусть X и Y — два множества. Закон F, согласно которому каждому элементу x из X поставлен в соответствие единственный элемент y из Y, называется отображением множества X в множество Y или функцией, заданной на X со значениями в Y.

http://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F_%28%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%29

Набор "не связанных между собой" точек очень даже попадает под это определение.

И, как уже сказал Kpd, после интерполяции получится многочлен степени n-1.

A
На сайте с 12.04.2007
Offline
9
#10
Kolyaj:

Набор "не связанных между собой" точек

Если хотябы одному иксу будет соответствовать хотя бы 2 игрека, то функцией это уже не будет.

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий