Files
StarStreet-Forecast/framegrafico.pas
2026-03-23 09:26:34 +00:00

407 lines
15 KiB
ObjectPascal

unit framegrafico;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, ExtCtrls, Astronomy, DateUtils, Graphics,
StdCtrls, LResources;
procedure calcolapianeti;
function FormattaOraDaMinutiGiorno(minutigiorno:integer):string;
type
{ TPianetiGraph }
TPianetiGraph = class(TFrame)
Label1: TLabel;
PaintBox1: TPaintBox;
procedure FrameMouseLeave(Sender: TObject);
procedure ImpostaTempoClick(Sender: TObject; Tempo:TDateTime; lat, long:double);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure PaintBox1Paint(Sender: TObject);
private
public
var colorform:TColor;
end;
type
TNomePianeta= (Sole, Luna, Mercurio, Venere, Marte, Giove, Saturno, Urano, Nettuno);
TPianeta= record
colore:Tcolor;
sorge:integer; //minuti da inizio giornata
tramonta:integer; //minuti da inizio giornata
distanza:double; //distanza in unità astronomiche
testo:string;
isinsky: boolean; // variabile che dice se l'oggetto è nel cielo nel caso sia l'alba che il tramonto non siano ottenibili
illumData:astro_illum_t;
case nome: TNomePianeta of //questo record genera i campi per il crepuscolo civile solo se il nome è Sole
Sole: (civildawn, civildusk, nauticaldawn, nauticaldusk, astronomicaldawn, astronomicaldusk :integer);
Luna, Mercurio, Venere, Marte, Giove, Saturno, Urano, Nettuno: ( );
end;
implementation
{$R *.lfm}
{ TPianetiGraph }
var
//Array dei vari oggetti celesti $00090909
oggetticelesti:array of TPianeta=
(( colore: $003AE1FE; sorge: 0; tramonta: 0; distanza: 0; testo: 'Sole'; isinsky: False; illumData:(); nome: Sole; civildawn: 0; civildusk:0; nauticaldawn:0; nauticaldusk:0; astronomicaldawn:0; astronomicaldusk:0 ),
( colore: $00EADBCD; sorge:0; tramonta: 0; distanza: 0; testo: 'Luna'; isinsky: False;illumData:(); nome: Luna;),
( colore: $00A1D11D; sorge:0; tramonta: 0; distanza: 0; testo: 'Mercurio'; isinsky: False;illumData:(); nome: Mercurio;),
( colore: $00D3D200; sorge:0; tramonta: 0; distanza: 0; testo: 'Venere'; isinsky: False;illumData:(); nome: Venere; ),
( colore: $005352EE; sorge: 0; tramonta: 0; distanza: 0; testo: 'Marte'; isinsky: False;illumData:(); nome: Marte;),
( colore: $00628EFF; sorge: 0; tramonta: 0; distanza: 0; testo: 'Giove'; isinsky: False;illumData:(); nome: Giove; ),
( colore: $00439FFF; sorge: 0; tramonta: 0; distanza: 0; testo: 'Saturno'; isinsky: False;illumData:(); nome: Saturno;),
( colore: $00FFA054; sorge: 0; tramonta: 0; distanza: 0; testo: 'Urano'; isinsky: False;illumData:(); nome: Urano;),
( colore: $00CD275F; sorge: 0; tramonta: 0; distanza: 0; testo: 'Nettuno'; isinsky: False;illumData:(); nome: Nettuno;)
);
oggetto:string;
durataora:double;
durataminuto:double;
duratamezzora:double;
durataorai:integer; //la durata ora per la variabile i
orafine:integer;
altezzarighe:double;
//variabili di posizione
latitudine:double;
longitudine:double;
altitudine:integer=500;
tempoinizio:TDateTime;//tempo di inizio della giornata coincide con le 0.0 della giornata corrente oppure quello impostato dall'utente
isFirstTime:boolean=True;
const
xtesto=10;
xgrafico=50; // cordinata x di inizio del grafico
distrighetop=30;
spesspianeti=13; //spessore righe sorgere e tramonto PianetiGraph
aggpospianeti=2; //aggiusta la posizione del rettangolo PianetiGraph rispetto al testo
ridpaint=60; //indica quanto è più piccolo in pixel il grafico (dal righello in poi) rispetto alla larghezza della paintbox
distrighellotop=25;
altezzarighello=6;
mezzorighello=5;
roundrett=5; //arrottondamento angoli rettangoli
procedure TPianetiGraph.PaintBox1Paint(Sender: TObject);
var
i:integer=1;
corpo:TPianeta;
orafine2:integer;
begin
if isFirstTime then
begin
tempoinizio:=EncodeDate(YearOf(Now), MonthOf(Now), DayOf(Now));
calcolapianeti;
isFirstTime:=False;
end;
orafine:=PaintBox1.Width-ridpaint+xgrafico; //calcola gli ultimi pixel da rappresentare nel righello
orafine2:=PaintBox1.Width-ridpaint;
durataora:=(PaintBox1.Width-ridpaint)/24; //calcola il numero di pixel che sono rappresentati da un ora
durataminuto:=durataora/60; //calcola il numero di pixel che rappresentano un minuto
duratamezzora:=(PaintBox1.Width-ridpaint)/48;
altezzarighe:=(PaintBox1.height/11); //calcola la distanza che vi è tra le diverse righe che rappresentano il sorg e il tramont dei PianetiGraph
PaintBox1.Canvas.Brush.Color:=colorform; //decide il colore di sfondo del canvas
PaintBox1.Canvas.Font.Color:=clWhite; //mette il font bianco di default perchè cambia colore dal tema chiaro a scuro del sistema
for corpo in oggetticelesti do //scrive i nomi degli oggetti celesti e rettangoli
begin
PaintBox1.Canvas.Pen.Color:=clWhite;
PaintBox1.Canvas.Font.Size:=11;
PaintBox1.Canvas.TextOut(xtesto,round(altezzarighe*i+distRighetop), copy(corpo.testo,0,3));
if corpo.nome= Sole then
begin //i crepuscoli vanno messi in ordine dall'astronomio al civile per non fare in modo che si sovrascrivano a vicenda
//crepuscolo astronomico
PaintBox1.Canvas.Brush.Color:=$00300A00;
PaintBox1.Canvas.Pen.Color:=clWhite;
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.astronomicaldusk/1440),round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+orafine2*corpo.astronomicaldawn/1440),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
//crepuscolo nautico
PaintBox1.Canvas.Brush.Color:=$009E2200;
PaintBox1.Canvas.Pen.Color:=clWhite;
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.nauticaldusk/1440),round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+orafine2*corpo.nauticaldawn/1440),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
//crepuscolo civile
PaintBox1.Canvas.Brush.Color:=$00FF3700;
PaintBox1.Canvas.Pen.Color:=clWhite;
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.civildusk/1440),round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+orafine2*corpo.civildawn/1440),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
end;
PaintBox1.Canvas.Brush.Color:=corpo.colore;
PaintBox1.Canvas.Pen.Color:=clWhite;
if (corpo.sorge=-1) and (corpo.tramonta>=0) then
begin
PaintBox1.Canvas.RoundRect(xgrafico,round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+(orafine2*corpo.tramonta/1440)),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
end else
begin
if (corpo.sorge>=0) and (corpo.tramonta=-1) then
begin
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.sorge/1440),round(altezzarighe*i+aggpospianeti+distrighetop),orafine,round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
end else
begin
if (corpo.sorge=-1) and (corpo.tramonta=-1) then
begin
if corpo.isinsky=True then
PaintBox1.Canvas.RoundRect(xgrafico,round(altezzarighe*i+aggpospianeti+distrighetop),orafine,round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
end else
begin
if corpo.sorge<corpo.tramonta then
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.sorge/1440),round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+orafine2*corpo.tramonta/1440),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett)
else
begin
PaintBox1.Canvas.RoundRect(xgrafico,round(altezzarighe*i+aggpospianeti+distrighetop),round(xgrafico+(orafine2*corpo.tramonta/1440)),round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
PaintBox1.Canvas.RoundRect(round(xgrafico+orafine2*corpo.sorge/1440),round(altezzarighe*i+aggpospianeti+distrighetop),orafine,round(altezzarighe*i+aggpospianeti+spesspianeti+distrighetop),roundrett,roundrett);
end;
end;
end;
end;
PaintBox1.Canvas.Brush.Color:=colorform; //decide il colore di sfondo del canvas
i:=i+1;
end;
for i:=0 to 24 do //crea le tacche delle ore
begin
durataorai:=round( durataora*i);
PaintBox1.Canvas.Pen.Color:=clwhite;
PaintBox1.Canvas.Line(durataorai+xgrafico,distrighellotop,durataorai+xgrafico,distrighellotop+altezzarighello);
PaintBox1.Canvas.Pen.Color:=clNone;
PaintBox1.Canvas.TextOut(durataorai+xgrafico-6,5, inttostr(i));
end;
for i:=0 to 23 do //crea le tacche delle mezzore
begin
durataorai:=round( durataora*i+duratamezzora);
PaintBox1.Canvas.Pen.Color:=clwhite;
PaintBox1.Canvas.Line(durataorai+xgrafico,distrighellotop+round(mezzorighello/2),durataorai+xgrafico,distrighellotop+round(mezzorighello));
end;
PaintBox1.Canvas.Line(xgrafico,distrighellotop+mezzorighello,orafine, distrighellotop+mezzorighello);//disegna la riga sulle tacche
end;
procedure TPianetiGraph.ImpostaTempoClick(Sender: TObject; Tempo:TDateTime; lat, long:double);
begin
tempoinizio:=Tempo;
latitudine:=lat;
longitudine:=long;
calcolapianeti;
PaintBox1.Refresh;
end;
procedure TPianetiGraph.FrameMouseLeave(Sender: TObject);
begin
Label1.Caption:='';
end;
var
stop:boolean;
procedure TPianetiGraph.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
elementi:TPianeta;
valoreriga: integer;
magnitudine:string;
fasepianetiinterni:string;
saturnoring:string;
orasorge:string;
oratramonta:string;
crepuscoli:string;
i:integer;
begin
i:=0;
for elementi in oggetticelesti do
begin
i:=i+1;
valoreriga:=round(altezzarighe*i+aggpospianeti+distrighetop);
if (Y>valoreriga) and (Y<valoreriga+spesspianeti) then
begin
if elementi.nome=Sole then
begin
crepuscoli:=' Crepuscoli:';
crepuscoli:=crepuscoli+' Astronomico '+ FormattaOraDaMinutiGiorno(elementi.astronomicaldusk)+ '-'+ FormattaOraDaMinutiGiorno(elementi.astronomicaldawn);
crepuscoli:=crepuscoli+' Nautico '+ FormattaOraDaMinutiGiorno(elementi.nauticaldusk)+ '-'+ FormattaOraDaMinutiGiorno(elementi.nauticaldawn);
crepuscoli:=crepuscoli+' Civile '+ FormattaOraDaMinutiGiorno(elementi.civildusk)+ '-'+ FormattaOraDaMinutiGiorno(elementi.civildawn);
end;
magnitudine:=' Magnitudine: '+ SysUtils.FormatFloat('0.00', elementi.illumData.mag);
if (elementi.nome=Mercurio) or (elementi.nome=Venere) then fasepianetiinterni:=' Fase: '+FormatFloat('0.00', elementi.illumData.phase_fraction) ;
if (elementi.nome=Saturno) then saturnoring:=' Inclinazione Anelli: '+FormatFloat('0.00', elementi.illumData.ring_tilt);
if elementi.sorge=-1 then orasorge:='--'
else orasorge:=FormattaOraDaMinutiGiorno(elementi.sorge);
if elementi.tramonta=-1 then oratramonta:='--'
else oratramonta:=FormattaOraDaMinutiGiorno(elementi.tramonta) ;
Label1.Caption:=elementi.testo+magnitudine+fasepianetiinterni+saturnoring+Crepuscoli+' Sorge alle: '+orasorge + ' Tramonta alle: ' + oratramonta+' Distanza '+SysUtils.FormatFloat('0.000',elementi.distanza)+'UA'; ;
break;
end
end;
end;
function FormattaOraDaMinutiGiorno(minutigiorno:integer):string;
begin
result:= SysUtils.FormatFloat('00',(minutigiorno div 60))+':'+ sysUtils.FormatCurr('00', (minutigiorno mod 60) );
end;
procedure calcolapianeti;
var
i:integer;
alba:TDateTime;
tramonto:TDateTime;
crepalba:TDateTime;//crepuscolo civile alba
creptram:TDateTime;//crepuscolo tramonto alba
minutidainizio:integer; //indica il numero di minuti da inizio giorno
numerocorpo:integer; //serve per corrispondenza tra gli enum in TPianeta e quelli contenuti in astro_body_t
ognicrepuscolo:TCrepuscolo;
datecrep:TDateTime;
segnaposto:integer;
albaerror:boolean=False; //variabili utilizzate per segnare in caso di errore;
tramontoerror:boolean=False;
altezzaoggetto:double=0;
begin
for i:=0 to 8 do //serve per corrispondenza tra gli enum in TPianeta e quelli contenuti in astro_body_t
begin
albaerror:=False;
tramontoerror:=False;
case oggetticelesti[i].nome of
Mercurio: numerocorpo:=0;
Venere: numerocorpo:=1;
Marte: numerocorpo:=3;
Giove: numerocorpo:=4;
Saturno: numerocorpo:=5;
Urano: numerocorpo:=6;
Nettuno: numerocorpo:=7;
Sole: numerocorpo:=9;
Luna: numerocorpo:=10;
end;
oggetticelesti[i].distanza:=astronomy.DistanzaOggetto(numerocorpo, latitudine, longitudine, altitudine, DateUtils.IncHour(tempoinizio, 12));
oggetticelesti[i].illumData:=astronomy.Illuminazione(numerocorpo, DateUtils.IncHour(tempoinizio, 12));
if oggetticelesti[i].nome=Sole then
begin
//il sole presenta anche i crepuscoli a differenza degli altri oggetti
for ognicrepuscolo in Tcrepuscolo do
begin
datecrep:=Astronomy.Crepuscolo(latitudine, longitudine, altitudine, 1, tempoinizio, ognicrepuscolo);
segnaposto:=DateUtils.MinutesBetween(tempoinizio, datecrep);
case ognicrepuscolo of
civildawn:oggetticelesti[i].civildawn:=segnaposto;
civildusk:oggetticelesti[i].civildusk:=segnaposto;
nauticaldawn:oggetticelesti[i].nauticaldawn:=segnaposto;
nauticaldusk:oggetticelesti[i].nauticaldusk:=segnaposto;
astronomicaldawn:oggetticelesti[i].astronomicaldawn:=segnaposto;
astronomicaldusk:oggetticelesti[i].astronomicaldusk:=segnaposto;
end;
end;
end;
try
alba:=Astronomy.TrovaSorgereOggetto(numerocorpo, latitudine, longitudine, altitudine, tempoinizio, 1);
except
on E:exception do
begin
albaerror:=True;
oggetticelesti[i].sorge:=-1;
end;
end;
try
tramonto:=Astronomy.TrovaTramontoOggetto(numerocorpo, latitudine, longitudine, altitudine, tempoinizio, 1);
except
on E:exception do
begin
tramontoerror:=True;
oggetticelesti[i].tramonta:=-1;
end;
end;
if albaerror=False then oggetticelesti[i].sorge:=DateUtils.MinutesBetween(tempoinizio, alba);
if tramontoerror=False then oggetticelesti[i].tramonta:=DateUtils.MinutesBetween(tempoinizio, tramonto);
if albaerror and tramontoerror then
begin
end;
altezzaoggetto:= astronomy.AltitudineOggetto(numerocorpo, latitudine, longitudine, altitudine, DateUtils.IncHour(tempoinizio, 12));
if altezzaoggetto>0 then
oggetticelesti[i].isinsky:=True else oggetticelesti[i].isinsky:=False;
end;
end;
end.