Coś mnie naszło na odświeżenie wiedzy z fizyki oraz programowania w PHP. Tylko jak to połączyć? Mam! W bardzo starych zasobach odkopałem bazę danych linii widmowych wszystkich (no prawie) pierwiastków. Baza jest w MySQL czyli jak do PHP to jak znalazł. Wstępnie postanowiłem jej nie wykorzystywać tylko wpisać wybrane linie w samym skrypcie PHP. Okazało się, że jest pewien problem. Otóż w bazie danych podana jest długość fali danych linii w nm. Jak to przeliczyć na RGB? Okazuje się, że dokładne odwzorowanie kolorów z długości fali na przestrzeń RGB nie jest możliwe w 100%. Wynika to oczywiście z zakresu przestrzeni barwnej. Ale nic. Gwardia umiera ale się nie poddaje. Udało mi się znaleźć przybliżony algorytm konwertujący długość fali na RGB.
Jest o bardzo prosty i składa się z dwóch funkcji (listing w PHP):
{
$intensity_max=255;
$gamma=0.8;
if ($color==0) return 0; else
return round($intensity_max*pow($color*$factor,$gamma));
}
function lambda2RGB($lambda){
if (($lambda>=380)&&($lambda<=439)) {$R=-($lambda-440)/60;$G=0;$B=1.0;} else
if (($lambda>=440)&&($lambda<=489)) {$R=0;$G=($lambda-440)/50;$B=1.0;} else
if (($lambda>=490)&&($lambda<=509)) {$R=0;$G=1;$B=-($lambda-510)/20;} else
if (($lambda>=510)&&($lambda<=579)) {$R=($lambda-510)/70;$G=1;$B=0;} else
if (($lambda>=580)&&($lambda<=644)) {$R=1;$G=-($lambda-645)/65;$B=0;} else
if (($lambda>=645)&&($lambda<=780)) {$R=1;$G=0;$B=0;} else {$R=0;$G=0;$B=0;}
if (($lambda>=380)&&($lambda<=419)) {$intensity=0.3+0.7*($lambda-380)/40;}
if (($lambda>=420)&&($lambda<=700)) {$intensity=1;}
if (($lambda>=701)&&($lambda<=780)) {$intensity=0.3+0.7*(780-$lambda)/80;}
$R=adjust($R,$intensity);
$G=adjust($G,$intensity);
$B=adjust($B,$intensity);
return array ($R,$G,$B);
}
Dalej to już z górki. Skrypt generujący widmo ciągłe światła białego.
//calculations
function adjust($color,$factor){
$intensity_max=255;
$gamma=0.8;
if ($color==0) return 0; else
return round($intensity_max*pow($color*$factor,$gamma));
}
function lambda2RGB($lambda){
if (($lambda>=380)&&($lambda<=439)) {$R=-($lambda-440)/60;$G=0;$B=1.0;} else
if (($lambda>=440)&&($lambda<=489)) {$R=0;$G=($lambda-440)/50;$B=1.0;} else
if (($lambda>=490)&&($lambda<=509)) {$R=0;$G=1;$B=-($lambda-510)/20;} else
if (($lambda>=510)&&($lambda<=579)) {$R=($lambda-510)/70;$G=1;$B=0;} else
if (($lambda>=580)&&($lambda<=644)) {$R=1;$G=-($lambda-645)/65;$B=0;} else
if (($lambda>=645)&&($lambda<=780)) {$R=1;$G=0;$B=0;} else {$R=0;$G=0;$B=0;}
if (($lambda>=380)&&($lambda<=419)) {$intensity=0.3+0.7*($lambda-380)/40;}
if (($lambda>=420)&&($lambda<=700)) {$intensity=1;}
if (($lambda>=701)&&($lambda<=780)) {$intensity=0.3+0.7*(780-$lambda)/80;}
$R=adjust($R,$intensity);
$G=adjust($G,$intensity);
$B=adjust($B,$intensity);
return array ($R,$G,$B);
}
// file type
header("Content-type: image/png");
// create image
$img = imagecreatetruecolor(800, 50);
// set colors
// draw line
for($i=380;$i<=780;$i++){
$x=2*$i-760;
list($a,$b,$c)=lambda2RGB($i);
$color = imagecolorallocate($img, $a, $b, $c);
imageline($img,$x,0,$x,50,$color);
imageline($img,$x+1,0,$x+1,50,$color);
}
// display image
imagepng($img);
// release image from memory
imagedestroy($img)
?>
Wynik działania:
Działa! Czas przetestować na liniach widmowych. Na warsztat idzie wodór (seria Blamera) i rtęć. Drobna modyfikacja skryptu (dla np. Hg):
// draw line
$lines=array(3983.931,4046.563, 4339.223,4347.494,4358.328,5128.442,5204.768,5425.253,5460.735,5677.105,5769.598,790.663,5871.279,5888.939, 6146.435,6149.475,7081.90,7346.508);
foreach($lines as $i){
$i=$i/10;
$x=2*$i-760;
list($a,$b,$c)=lambda2RGB($i);
$color = imagecolorallocate($img, $a, $b, $c);
//imageline($img,$x,0,$x,50,$color);
imageline($img,$x+1,0,$x+1,50,$color);
}
I wyniki są bardzo obiecujące.
|
Wodór (seria Blamera) |
|
Rtęć Hg I i Hg II |
Na początek zostaje uwzględnienie intensywności linii ale o tym w części 2.