immagini.php
<?php
declare(strict_types=1);
class gf_cartesiano
{
// dimensioni immagine totale
public int $_x_size_;
public int $_y_size_;
// coordinate origine assi
public int $_x0_;
public int $_y0_;
// dimensioni asse x
public int $_xi_;
public int $_xf_;
public int $_x_axis_;
// dimensioni asse y
public int $_yi_;
public int $_yf_;
public int $_y_axis_;
// l'immagine
public GdImage $image;
// qualche colore
public readonly int $white;
public readonly int $black;
public readonly int $red;
public readonly int $blue;
public readonly int $green;
public readonly int $magenta;
public readonly int $yellow;
public readonly int $darkgreen;
public readonly int $darkorange;
// settata nel costruttore, ma non usata
public float|int $scale;
public function __construct(float|int &$x_axis, float|int &$y_axis)
// costruttore
{
// settta le dimensioni dell'immagine
$this->_x_size_ = 480; // 480;
$this->_y_size_ = 480; // 480;
// coordinate origine assi
$this->_x0_ = 30;
$this->_y0_ = $this->_y_size_ - 30;
// dimensioni asse x
$this->_xi_ = 10;
$this->_xf_ = $this->_x_size_ - $this->_xi_;
$this->_x_axis_ = $this->_xf_ - $this->_x0_ - 10;
$x_axis = $this->_x_axis_;
// dimensioni asse y
$this->_yi_ = 10;
$this->_yf_ = $this->_y_size_ - $this->_yi_;
$this->_y_axis_ = $this->_yf_ - $this->_y0_ - 10;
$y_axis = $this->_y_axis_;
// crea lo sfondo
$this->image = imagecreatetruecolor($this->_x_size_, $this->_y_size_);
// alloca i colori
$this->white = (int)ImageColorAllocate($this->image, 255, 255, 255);
$this->black = (int)ImageColorAllocate($this->image, 0, 0, 0);
//$this->red = ImageColorAllocate($this->image, 255, 0, 0);
$this->red = (int)ImageColorAllocate($this->image, 127, 0, 0);
$this->green = (int)ImageColorAllocate($this->image, 0, 255, 0);
$this->blue = (int)ImageColorAllocate($this->image, 0, 0, 255);
$this->magenta = (int)ImageColorAllocate($this->image, 255, 0, 255);
$this->yellow = (int)ImageColorAllocate($this->image, 255, 255, 0);
$this->darkgreen = (int)ImageColorAllocate($this->image, 0, 100, 0);
//$this->darkorange = ImageColorAllocate($this->image, 255, 127, 0);
$this->darkorange = (int)ImageColorAllocate($this->image, 255, 63, 63);
// assegna un valore a caso a scale
$this->scale = 1;
// ritorna il puntatore all'immagine
// return $this->image;
}
public function fq_col(int $col): void
// colora il primo quadrante
{
$tile = imageCreateFromPNG('images/regione_amm.png');
if (!$tile) {
die ('Unable to open image');
}
imageSetTile($this->image, $tile);
imagefilledrectangle($this->image, 0, 0, $this->_x_size_, $this->_y_size_, $this->white);
imagefilledrectangle($this->image, 30, 20, $this->_x_size_ - 20, $this->_x_size_ - 30, IMG_COLOR_TILED);
}
/** @param array<int, float|int> $vertici */
public function assi(array $vertici, float|int $scale): void
// disegna gli assi e scrive i valori
{
// disegna asse x
imageline($this->image, $this->_xi_, $this->_y0_, $this->_xf_, $this->_y0_, $this->black);
// disegna frecce asse x
imageline($this->image, $this->_xf_ - 10, $this->_y0_ - 10, $this->_xf_, $this->_y0_, $this->black);
imageline($this->image, $this->_xf_ - 10, $this->_y0_ + 10, $this->_xf_, $this->_y0_, $this->black);
// scrivi O nell'origine
imagechar($this->image, 3, $this->_x0_ - 25, $this->_y0_ + 10, "O", $this->black);
// disegna lettere asse x e stanghette
imagechar($this->image, 3, $this->_xf_ - 10, $this->_y0_ + 10, "x", $this->black);
imagechar($this->image, 2, $this->_xf_, $this->_y0_ + 15, "1", $this->black);
for ($i = 0; $i < count($vertici); $i += 2) if ($vertici[$i] > 0) {
$x = $this->map_x($vertici[$i], $scale);
imageline($this->image, (int)$x, $this->_y0_, (int)$x, $this->_y0_ + 5, $this->black);
if (abs(floor($vertici[$i]) - $vertici[$i]) <= 0.00001) $lettere = sprintf("%d", $vertici[$i]);
else $lettere = sprintf("%.2f", $vertici[$i]);
imagestring($this->image, 3, (int)$x - 10, $this->_y0_ + 10, $lettere, $this->black);
}
// disegna asse y
imageline($this->image, $this->_x0_, $this->_yi_, $this->_x0_, $this->_yf_, $this->black);
// disegna frecce asse y
imageline($this->image, $this->_x0_ - 10, $this->_yi_ + 10, $this->_x0_, $this->_yi_, $this->black);
imageline($this->image, $this->_x0_ + 10, $this->_yi_ + 10, $this->_x0_, $this->_yi_, $this->black);
// disegna lettere asse y
imagechar($this->image, 3, $this->_x0_ - 25, $this->_yi_ + 5, "x", $this->black);
imagechar($this->image, 2, $this->_x0_ - 15, $this->_yi_ + 10, "2", $this->black);
for ($i = 1; $i < count($vertici); $i += 2) if ($vertici[$i] > 0) {
$y = $this->map_y($vertici[$i], $scale);
imageline($this->image, $this->_x0_ - 5, (int)$y, $this->_x0_, (int)$y, $this->black);
if (abs(floor($vertici[$i]) - $vertici[$i]) <= 0.00001) $lettere = sprintf("%d", $vertici[$i]);
else $lettere = sprintf("%.2f", $vertici[$i]);
imagestring($this->image, 3, $this->_x0_ - 30, (int)$y, $lettere, $this->black);
}
}
public function map_x(float|int $vx, float|int $scale): int
/* ritorna il valore della coordinata x sull'immagine corrispondente al punto
di coordinata vx nell'asse cartesiano, fissato il parametro di scala */
{
return (int)($this->_x0_ + round($scale * $vx));
}
public function map_y(float|int $vy, float|int $scale): int
/* ritorna il valore della coordinata y sull'immagine corrispondente al punto
di coordinata vy nell'asse cartesiano, fissato il parametro di scala */
{
return (int)($this->_y0_ - round($scale * $vy));
}
public function freccia(float|int $scale, float|int $vxi, float|int $vyi, float|int $vxf, float|int $vyf, int $col): void
/* disegna la freccia P-Q fra P=(vxi, vyi) e q=(vxf, vyf) con ampiezza 45 gradi*/
{
/* R R __. P
45� \ /\ S
Q ----------> P / angolo di cui calcolo sin e cos
45� / _______ /)______________
S Q x
*/
$xr = 0;
$yr = 0;
$xs = 0;
$ys = 0;
// calcolo nuove coordinate
$xi = $this->map_x($vxi, $scale);
$xf = $this->map_x($vxf, $scale);
$yi = $this->map_y($vyi, $scale);
$yf = $this->map_y($vyf, $scale);
// trasliamo P-Q nell'origine per fare i conti
$x = $xf - $xi;
$y = -($yf - $yi);
$modulo = sqrt($x * $x + $y * $y);
// calcola seno e coseno dell'angolo fra il segmento e l'asse x
if (!$modulo)
return;
$sin_ = $y / $modulo;
$cos_ = $x / $modulo;
// calcola gli estremi dei segmenti delle frecce
// r rotazione di 45deg del vettore di modulo 10 e direzione di Q-P
$this->ruota(-10 * $cos_, -10 * $sin_, $xr, $yr, M_PI / 6);
$xr += $xf;
$yr = $yf - $yr;
// s rotazione di -45� del vettore di modulo 10 e direzione di Q-P
$this->ruota(-10 * $cos_, -10 * $sin_, $xs, $ys, 11 * M_PI / 6);
$xs += $xf;
$ys = $yf - $ys;
// disegna il segmento
imageline($this->image, (int)$xi, (int)$yi, (int)$xf, (int)$yf, $col);
imageline($this->image, (int)$xi - 1, (int)$yi, (int)$xf - 1, (int)$yf, $col);
imageline($this->image, (int)$xi + 1, (int)$yi, (int)$xf + 1, (int)$yf, $col);
imageline($this->image, (int)$xi, (int)$yi - 1, (int)$xf, (int)$yf - 1, $col);
imageline($this->image, (int)$xi, (int)$yi + 1, (int)$xf + 1, (int)$yf + 1, $col);
imagefilledpolygon($this->image, array($xr, $yr, $xs, $ys, $xf, $yf), 3, $col);
//imageline($this->image,$xr,$yr,$xf,$yf,$col);
//imageline($this->image,$xs,$ys,$xf,$yf,$col);
return;
}
public function ruota(float|int $x, float|int $y, float|int &$xr, float|int &$yr, float $alpha): void
// ruota (x, y)-(0, 0) di un angolo alpha
{
$xr = $x * cos($alpha) - $y * sin($alpha);
$yr = $y * cos($alpha) + $x * sin($alpha);
}
public function cerchio(float|int $scale, float|int $vx0, float|int $vy0, float|int $l, int $col): void
/* disegna una circonferenza di raggio r pixel e centro P=(vx, vy) */
{
$x0 = $this->map_x($vx0, $scale);
$y0 = $this->map_y($vy0, $scale);
$l2 = round($l / 2);
//imagefilledellipse($this->image,$x0,$y0,$r,$r,$col); // non gestita da vecchie gd
//imagefilledrectangle($this->image, $x0 - $l2, $y0 - $l2, $x0 + $l2, $y0 + $l2, $col);
imagefilledrectangle($this->image, (int)($x0 - 3 * $l2 / 2), (int)($y0 - 3 * $l2 / 2), (int)($x0 + 3 * $l2 / 2), (int)($y0 + 3 * $l2 / 2), $col);
}
public function ping(string $name): void
// scrive l'immagine in formato PNG nel file di nome $name
{
imagepng($this->image, $name);
}
public function plotta_disequazione(float|int $ax, float|int $ay, float|int $b, string $lge, float|int $scale, int $col): int
/* disegna i segmenti corrispondenti alla dis/equazione immessa e cancella
la parte che non verifica la disequazione usando il colore $col */
{ // ax x + ay y lge b
// costanti
$max = $this->_x_axis_ / $scale;
$p0x = 0;
$p0y = 0; // (sx,basso)
$vx0 = 0;
$vx1 = 0;
$vy0 = 0;
$vy1 = 0;
$a = 0;
$bTmp = 0;
$array1 = [];
$p1x = $max;
$p1y = 0; // (dx,basso)
$p2x = $max;
$p2y = $max; // (dx, alto)
$p3x = 0;
$p3y = $max; // (sx, alto)
$p4x = 0;
$p4y = 0;
if ($ax == 0) { // ay y = b
if ($ay == 0) return 0;
$vx0 = 0;
$vx1 = $max;
$vy0 = $b / $ay;
$vy1 = $vy0;
// se si tratta di un'equazione, scrivi l'immagine e ritorna
if (!strcmp($lge, "=")) {
$this->line($scale, $vx0, $vy0, $vx1, $vy1, $col);
return 0;
}
// si tratta di una disequazione ay y <> b
if (strstr($lge, ">")) if ($ay > 0) $cancella_sotto = true;
else $cancella_sotto = false;
else if ($ay > 0) $cancella_sotto = false;
else $cancella_sotto = true;
if ($cancella_sotto) {
if ($vy0 > 0) imagefilledrectangle($this->image, $this->map_x(0, $scale), $this->map_y($vy0, $scale), $this->map_x($max, $scale), $this->map_y(0, $scale), $col);
} else if ($vy0 > 0) imagefilledrectangle($this->image, $this->map_x(0, $scale), $this->map_y($max, $scale), $this->map_x($max, $scale), $this->map_y($vy0, $scale), $col);
else imagefilledrectangle($this->image, $this->map_x(0, $scale), $this->map_y($max, $scale), $this->map_x($max, $scale), $this->map_y(0, $scale), $col);
return 0;
}
if ($ay) {
$m = -$ax / $ay;
$q = $b / $ay;
} else { // ax x = b
$vx0 = $b / $ax;
$vx1 = $vx0;
$vy0 = 0;
$vy1 = $max;
// se si tratta di un'equazione, scrivi l'immagine e ritorna
if (!strcmp($lge, "=")) {
$this->line($scale, $vx0, $vy0, $vx1, $vy1, $col);
return 0;
}
// si tratta di una disequazione
if (strstr($lge, ">")) if ($ax > 0) $cancella_sx = true;
else $cancella_sx = false;
else if ($ax > 0) $cancella_sx = false;
else $cancella_sx = true;
if ($cancella_sx) {
if ($vx0 > 0) imagefilledrectangle($this->image, $this->map_x(0, $scale), $this->map_y($max, $scale), $this->map_x($vx0, $scale), $this->map_y(0, $scale), $col);
} else if ($vx0 > 0) imagefilledrectangle($this->image, $this->map_x($vx0, $scale), $this->map_y($max, $scale), $this->map_x($max, $scale), $this->map_y(0, $scale), $col);
else imagefilledrectangle($this->image, $this->map_x(0, $scale), $this->map_y($max, $scale), $this->map_x($max, $scale), $this->map_y(0, $scale), $col);
return 0;
}
// setta i vertici della retta ax x + ay y = b
if ($m >= 0) if ($q >= 0) {
$vx0 = 0;
$vy0 = $q;
if (($vy1 = $m * $max + $q) < $max) {
$vx1 = $max;
} else {
$vy1 = $max;
$vx1 = ($max - $q) / $m;
}
} else {
$vx0 = $b / $ax;
$vy0 = 0;
if (($vy1 = $m * $max + $q) < $max) {
$vx1 = $max;
} else {
$vy1 = $max;
$vx1 = ($max - $q) / $m;
}
} else { // m<0
if ($q >= 0) {
$vx0 = 0;
$vy0 = $q;
if (($vy1 = $m * $max + $q) > 0) {
$vx1 = $max;
} else {
$vy1 = 0;
$vx1 = $b / $ax;
}
}
}
// se si tratta di un'equazione, scrivi l'immagine e ritorna
if (!strcmp($lge, "=")) {
$this->line($scale, $vx0, $vy0, $vx1, $vy1, $col);
return 0;
}
// si tratta di una disequazione
if (strstr($lge, ">")) if ($ay > 0) $cancella_sotto = true;
else $cancella_sotto = false;
else if ($ay > 0) $cancella_sotto = false;
else $cancella_sotto = true;
// echo "<br /> y = " . $m . "x + " . $q . "<br />\n";
// echo "<br /> cancella_sotto = " . (bool)(isset($cancella_sotto) && $cancella_sotto) . "<br />\n";
// echo "<br /> isset(cancella_sotto) = " . isset($cancella_sotto) . "<br />\n";
if ($m >= 0) // m >= 0
if ($q >= 0) { // m, q >= 0
if (!$cancella_sotto) { // m, q >= 0: colora il poligono piu' alto
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p2x, $p2y, $p3x, $p3y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p3x, $p3y);
} else { // m, q >= 0: colora il poligono in basso
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p1x, $p1y, $p0x, $p0y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p2x, $p2y, $p1x, $p1y, $p0x, $p0y);
}
} else { // m>=0, q<0
if (!$cancella_sotto) { // m>=0, q<0: alto
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p2x, $p2y, $p3x, $p3y, $p0x, $p0y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p3x, $p3y, $p0x, $p0y);
} else { // m>=0, q<0: basso
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p1x, $p1y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p2x, $p2y, $p1x, $p1y);
}
} else
// m < 0
if ($q >= 0) { // m < 0, q >= 0
if (!$cancella_sotto) { // m < 0, q >= 0: alto
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p2x, $p2y, $p3x, $p3y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p1x, $p1y, $p2x, $p2y, $p3x, $p3y);
} else { // m < 0, q >= 0: basso
if ($vx1 == $max) $array = array($vx0, $vy0, $vx1, $vy1, $p1x, $p1y, $p0x, $p0y);
else $array = array($vx0, $vy0, $vx1, $vy1, $p0x, $p0y);
}
} else { // m, q < 0
if (!$cancella_sotto) { // m>=0, q<0: alto
if ($vx1 == $max) $array = array($p0x, $p0y, $p1x, $p1y, $p2x, $p2y, $p3x, $p3y, $p4x, $p4y);
}
}
if (isset($array)) {
for ($i = 0; $i < count($array);) {
$array1[$i] = $this->map_x($array[$i], $scale);
$array1[$i + 1] = $this->map_y($array[$i + 1], $scale);
//imagearc($this->image, $array1[$i], $array1[$i+1],1,1,0,360,$this->blue);
$i += 2;
}
imagefilledpolygon($this->image, $array1, (int)(count($array1) / 2), $col);
unset($array);
unset($array1);
}
return 0;
}
public function line(float|int $scale, float|int $vxi, float|int $vyi, float|int $vxf, float|int $vyf, int $col): void
/* disegna il segmento corrispondente a quello PQ fra P=(vxi, vyi) e q=(vxf, vyf) */
{
// calcolo nuove coordinate
$xi = $this->map_x($vxi, $scale);
$xf = $this->map_x($vxf, $scale);
$yi = $this->map_y($vyi, $scale);
$yf = $this->map_y($vyf, $scale);
// disegna il segmento
imageline($this->image, (int)$xi, (int)$yi, (int)$xf, (int)$yf, $col);
imageline($this->image, (int)$xi - 1, (int)$yi, (int)$xf - 1, (int)$yf, $col);
imageline($this->image, (int)$xi + 1, (int)$yi, (int)$xf + 1, (int)$yf, $col);
imageline($this->image, (int)$xi, (int)$yi - 1, (int)$xf, (int)$yf - 1, $col);
imageline($this->image, (int)$xi, (int)$yi + 1, (int)$xf, (int)$yf + 1, $col);
}
}
class grafico extends gf_cartesiano
{
public string $basename;
public string $baseurl;
public string $middlename;
public string $extension = ".png";
/** @var array<int, float|int> */
public array $vertici;
public float $grad_x;
public float $grad_y;
/**
* @param array<mixed> $_a
* @param array<mixed> $_b
* @param array<mixed> $_c
* @param array<mixed> $lge
*/
public function __construct(array $_a, array $_b, array $_c, array $lge, bool $cambia_segno_gradiente, string $name, string $urlname = "")
{
$asse_x = 0;
$asse_y = 0;
$a = [];
$b = [];
parent::__construct($asse_x, $asse_y);
/* sostituisci in $a, $b, $c i valori agli oggetti frazione */
for ($i = 1; $i < count($_b) + 1; $i++) {
$b[$i] = $_b[$i]->value();
for ($j = 1; $j < 3; $j++) $a[$i][$j] = $_a[$i][$j]->value();
}
for ($j = 1; $j < 3; $j++) $c[$j] = $_c[$j]->value();
if ($cambia_segno_gradiente) {
$this->grad_x = -$c[1];
$this->grad_y = -$c[2];
} else {
$this->grad_x = $c[1];
$this->grad_y = $c[2];
}
$this->basename = $name;
$this->baseurl = $urlname !== "" ? $urlname : $name;
// $this->image = $this->gf_cartesiano ($asse_x, $asse_y);
$this->fq_col($this->yellow);
$vertici = array();
$this->trova_vertici($a, $b, $vertici);
$max = $this->cerca_max($vertici) * 1.1;
$this->scale = $asse_x / $max;
for ($i = 1; $i < count($b) + 1; $i++) {
$this->plotta_disequazione($a[$i][1], $a[$i][2], $b[$i], $lge[$i], $this->scale, $this->white);
// $this->ping($name . "___" $i);
}
for ($i = 1; $i < count($b) + 1; $i++) $this->plotta_disequazione($a[$i][1], $a[$i][2], $b[$i], "=", $this->scale, $this->blue);
$this->gradiente();
$this->assi($vertici, $this->scale);
$filename = $this->basename . $this->extension;
$this->ping($filename);
}
/**
* @param array<mixed> $a
* @param array<mixed> $b
* @param array<int, float|int> $vertici
*/
public function trova_vertici(array $a, array $b, array &$vertici): void
{
// numero di equazioni
$m = count($b);
$vertici = array_fill(0, (int)(($m * $m + 3 * $m) / 2 + 1), 0);
// dove incidono le rette
for ($k = 0, $i = 1; $i < $m + 1; $i++) for ($j = $i + 1; $j < $m + 1; $j++) {
// le x
if ($a[$i][1] * $a[$j][2] != $a[$j][1] * $a[$i][2]) $vertici[$k] = ($a[$j][2] * $b[$i] - $a[$i][2] * $b[$j]) / ($a[$i][1] * $a[$j][2] - $a[$j][1] * $a[$i][2]);
else $vertici[$k] = 0;
$k++;
// le y
if ($a[$i][2] != 0) $vertici[$k] = ($b[$i] - $a[$i][1] * $vertici[$k - 1]) / $a[$i][2];
else $vertici[$k] = 0;
$k++;
// echo "$i ∩ $j = (" . $vertici[$k-2] . ", " . $vertici[$k - 1] . ") <br />\n";
}
// aggiungiamo intersezioni con gli assi
for ($i = 1; $i < $m + 1; $i++) {
if (!isset($a[$i][1]) || $a[$i][1] != 0) {
$vertici[$k++] = $b[$i] / $a[$i][1];
$vertici[$k++] = 0;
} //else {
// $vertici[$k++]=0;
// echo "$i ∩ _0_ = (" . $vertici[$k-2] . ", " . $vertici[$k - 1] . ") <br />\n";
if (!isset($a[$i][2]) || $a[$i][2] != 0) {
$vertici[$k++] = 0;
$vertici[$k++] = $b[$i] / $a[$i][2];
} // else
// $vertici[$k++]=0;
// echo "_0_ ∩ $i = (" . $vertici[$k-2] . ", " . $vertici[$k - 1] . ") <br />\n";
}
}
/** @param array<int, float|int> $vertici */
public function cerca_max(array &$vertici): float|int
{
$max = $vertici[0];
for ($i = 1; $i < count($vertici); $i++) if ($vertici[$i] > $max) $max = $vertici[$i];
// $max e' il max fra le intercette e i valori di x e di y dei vertici
return $max;
}
public function gradiente(): void
{
$this->freccia($this->scale, 0, 0, $this->grad_x, $this->grad_y, $this->magenta);
}
public function passo(float|int $xi, float|int $yi, float|int $xf, float|int $yf, int $passo, string &$name): void
{
$filename = $this->basename . $passo;
$name = $this->baseurl . $passo;
/* la perpendicolare al gradiente passante per xf, yf */
$this->plotta_disequazione($this->grad_x, $this->grad_y, ($xf * $this->grad_x + $yf * $this->grad_y), "=", $this->scale, $this->darkgreen);
$this->cerchio($this->scale, $xf, $yf, 6, $this->red);
$this->freccia($this->scale, $xi, $yi, $xf, $yf, $this->darkorange);
$this->ping($filename . ".png");
$this->gradiente();
$this->cerchio($this->scale, $xf, $yf, 6, $this->red);
}
}