Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Определение восхода и захода солнца и луны

01.01.2007

Автор: Александр Ермолаев

program sunproject;
 
uses
  Forms,
  main in 'main.pas' {Sun};
 
{$R *.RES}
 
begin
  Application.Initialize;
  Application.Title := 'Sun';
  Application.CreateForm(TSun, Sun);
  Application.Run;
end.
object Sun: TSun
  Left = 210
    Top = 106
    BorderIcons = [biSystemMenu, biMinimize]
    BorderStyle = bsSingle
    Caption = 'Sun'
    ClientHeight = 257
    ClientWidth = 299
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OldCreateOrder = False
    Position = poDesktopCenter
    OnCreate = CreateForm
    PixelsPerInch = 96
    TextHeight = 13
    object GroupBoxInput: TGroupBox
    Left = 4
      Top = 4
      Width = 173
      Height = 93
      Caption = ' Ввод '
      TabOrder = 0
      object LabelLongitude: TLabel
      Left = 35
        Top = 44
        Width = 78
        Height = 13
        Alignment = taRightJustify
        Caption = 'Долгота (град):'
    end
    object LabelTimeZone: TLabel
      Left = 13
        Top = 68
        Width = 100
        Height = 13
        Alignment = taRightJustify
        Caption = 'Часовая зона (час):'
    end
    object LabelAtitude: TLabel
      Left = 40
        Top = 20
        Width = 73
        Height = 13
        Alignment = taRightJustify
        Caption = 'Широта (град):'
    end
    object EditB5: TEdit
      Tag = 1
        Left = 120
        Top = 16
        Width = 37
        Height = 21
        TabOrder = 0
        Text = '0'
    end
    object EditL5: TEdit
      Tag = 2
        Left = 120
        Top = 40
        Width = 37
        Height = 21
        TabOrder = 1
        Text = '0'
    end
    object EditH: TEdit
      Tag = 3
        Left = 120
        Top = 64
        Width = 37
        Height = 21
        TabOrder = 2
        Text = '0'
    end
  end
  object GroupBoxCalendar: TGroupBox
    Left = 184
      Top = 4
      Width = 109
      Height = 93
      Caption = ' Календарь '
      TabOrder = 1
      object LabelD: TLabel
      Left = 19
        Top = 20
        Width = 30
        Height = 13
        Alignment = taRightJustify
        Caption = 'День:'
    end
    object LabelM: TLabel
      Left = 13
        Top = 44
        Width = 36
        Height = 13
        Alignment = taRightJustify
        Caption = 'Месяц:'
    end
    object LabelY: TLabel
      Left = 28
        Top = 68
        Width = 21
        Height = 13
        Alignment = taRightJustify
        Caption = 'Год:'
    end
    object EditD: TEdit
      Tag = 1
        Left = 56
        Top = 16
        Width = 37
        Height = 21
        TabOrder = 0
        Text = '0'
    end
    object EditM: TEdit
      Tag = 2
        Left = 56
        Top = 40
        Width = 37
        Height = 21
        TabOrder = 1
        Text = '0'
    end
    object EditY: TEdit
      Tag = 3
        Left = 56
        Top = 64
        Width = 37
        Height = 21
        TabOrder = 2
        Text = '0'
    end
  end
  object ButtonCalc: TButton
    Left = 12
      Top = 227
      Width = 169
      Height = 25
      Caption = '&Вычислить'
      TabOrder = 2
      OnClick = ButtonCalcClick
  end
  object ListBox: TListBox
    Left = 4
      Top = 104
      Width = 289
      Height = 117
      ItemHeight = 13
      TabOrder = 3
  end
  object ButtonClear: TButton
    Left = 192
      Top = 227
      Width = 91
      Height = 25
      Caption = '&Очистить'
      TabOrder = 4
      OnClick = ButtonClearClick
  end
end
{
Программа вычисляет время восхода и захода
солнца по дате (с точностью до минуты) в пределах
нескольких текущих столетий. Производит корректировку, если
географическая
 
точка находится в арктическом или антарктическом регионе, где заход
или восход солнца
 
на текущую дату может не состояться. Вводимые данные: положительная
северная широта и
 
отрицательная западная долгота. Часовой пояс указывается относительно
Гринвича
 
(например, 5 для EST и 4 для EDT). Алгоритм обсуждался в
"Sky & Telescope" за август 1994, страница 84.
 
}
 
unit main;
 
interface
 
uses
 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs,
 
  StdCtrls;
 
type
 
  TSun = class(TForm)
    GroupBoxInput: TGroupBox;
    LabelLongitude: TLabel;
    EditB5: TEdit;
    EditL5: TEdit;
    LabelTimeZone: TLabel;
    EditH: TEdit;
    GroupBoxCalendar: TGroupBox;
    LabelD: TLabel;
    LabelM: TLabel;
    LabelY: TLabel;
    EditD: TEdit;
    EditM: TEdit;
    EditY: TEdit;
    ButtonCalc: TButton;
    ListBox: TListBox;
    ButtonClear: TButton;
    LabelAtitude: TLabel;
    procedure Calendar; // Календарь
    procedure GetTimeZone; // Получение часового пояса
    procedure PosOfSun; // Получаем положение солнца
    procedure OutInform; // Процедура вывода информации
    procedure PossibleEvents(Hour: integer); // Возможные события на
    полученный час
 
    procedure GetDate; //Получить значения даты
    procedure GetInput; //Получить значения широты,...
    procedure ButtonCalcClick(Sender: TObject);
    procedure CreateForm(Sender: TObject);
    procedure ButtonClearClick(Sender: TObject);
  private
    function Sgn(Value: Double): integer; // Сигнум
  public
    { Public declarations }
  end;
 
var
 
  Sun: TSun;
  st: string;
  aA, aD: array[1..2] of double;
  B5: integer;
  L5: double;
  H: integer;
  Z, Z0, Z1: double;
  D: double;
  M, Y: integer;
  A5, D5, R5: double;
  J3: integer;
  T, T0, TT, T3: double;
  L0, L2: double;
  H0, H1, H2, H7, N7, D7: double;
  H3, M3: integer;
  M8, W8: double;
  A, B, A0, D0, A2, D1, D2, DA, DD: double;
  E, F, J, S, C, P, L, G, V, U, W: double;
  V0, V1, V2: double;
  C0: integer;
  AZ: double;
 
const
 
  P2 = Pi * 2; // 2 * Pi
  DR = Pi / 180; // Радиан на градус
  K1 = 15 * DR * 1.0027379;
 
implementation
 
{$R *.DFM}
 
function TSun.Sgn(Value: Double): integer;
begin
 
  {if Value = 0 then} Result := 0;
  if Value > 0 then
    Result := 1;
  if Value < 0 then
    Result := -1;
end;
 
procedure TSun.Calendar;
begin
 
  G := 1;
  if Y < 1583 then
    G := 0;
  D1 := Trunc(D);
  F := D - D1 - 0.5;
  J := -Trunc(7 * (Trunc((M + 9) / 12) + Y) / 4);
  if G = 1 then
  begin
    S := Sgn(M - 9);
    A := Abs(M - 9);
    J3 := Trunc(Y + S * Trunc(A / 7));
    J3 := -Trunc((Trunc(J3 / 100) + 1) * 3 / 4);
  end;
  J := J + Trunc(275 * M / 9) + D1 + G * J3;
  J := J + 1721027 + 2 * G + 367 * Y;
  if F >= 0 then
    Exit;
  F := F + 1;
  J := J - 1;
end;
 
procedure TSun.GetTimeZone;
begin
 
  T0 := T / 36525;
  S := 24110.5 + 8640184.813 * T0;
  S := S + 86636.6 * Z0 + 86400 * L5;
  S := S / 86400;
  S := S - Trunc(S);
  T0 := S * 360 * DR;
end;
 
procedure TSun.PosOfSun;
begin
 
  //      Фундаментальные константы
  //  (Van Flandern & Pulkkinen, 1979)
  L := 0.779072 + 0.00273790931 * T;
  G := 0.993126 + 0.0027377785 * T;
  L := L - Trunc(L);
  G := G - Trunc(G);
  L := L * P2;
  G := G * P2;
  V := 0.39785 * Sin(L);
  V := V - 0.01000 * Sin(L - G);
  V := V + 0.00333 * Sin(L + G);
  V := V - 0.00021 * TT * Sin(L);
  U := 1 - 0.03349 * Cos(G);
  U := U - 0.00014 * Cos(2 * L);
  U := U + 0.00008 * Cos(L);
  W := -0.00010 - 0.04129 * Sin(2 * L);
  W := W + 0.03211 * Sin(G);
  W := W + 0.00104 * Sin(2 * L - G);
  W := W - 0.00035 * Sin(2 * L + G);
  W := W - 0.00008 * TT * Sin(G);
 
  // Вычисление солнечных координат
  S := W / Sqrt(U - V * V);
  A5 := L + ArcTan(S / Sqrt(1 - S * S));
  S := V / Sqrt(U);
  D5 := ArcTan(S / Sqrt(1 - S * S));
  R5 := 1.00021 * Sqrt(U);
end;
 
procedure TSun.PossibleEvents(Hour: integer);
var
  num: string;
begin
 
  st := '';
  L0 := T0 + Hour * K1;
  L2 := L0 + K1;
  H0 := L0 - A0;
  H2 := L2 - A2;
  H1 := (H2 + H0) / 2; // Часовой угол,
  D1 := (D2 + D0) / 2; // наклон в получасе
  if Hour <= 0 then
    V0 := S * Sin(D0) + C * Cos(D0) * Cos(H0) - Z;
  V2 := S * Sin(D2) + C * Cos(D2) * Cos(H2) - Z;
  if Sgn(V0) = Sgn(V2) then
    Exit;
  V1 := S * Sin(D1) + C * Cos(D1) * Cos(H1) - Z;
  A := 2 * V2 - 4 * V1 + 2 * V0;
  B := 4 * V1 - 3 * V0 - V2;
  D := B * B - 4 * A * V0;
  if D < 0 then
    Exit;
  D := Sqrt(D);
  if (V0 < 0) and (V2 > 0) then
    st := st + 'Восход солнца в ';
  if (V0 < 0) and (V2 > 0) then
    M8 := 1;
  if (V0 > 0) and (V2 < 0) then
    st := st + 'Заход солнца в ';
  if (V0 > 0) and (V2 < 0) then
    W8 := 1;
  E := (-B + D) / (2 * A);
  if (E > 1) or (E < 0) then
    E := (-B - D) / (2 * A);
  T3 := Hour + E + 1 / 120; // Округление
  H3 := Trunc(T3);
  M3 := Trunc((T3 - H3) * 60);
  Str(H3: 2, num);
  st := st + num + ':';
  Str(M3: 2, num);
  st := st + num;
  H7 := H0 + E * (H2 - H0);
  N7 := -Cos(D1) * Sin(H7);
  D7 := C * Sin(D1) - S * Cos(D1) * COS(H7);
  AZ := ArcTan(N7 / D7) / DR;
  if (D7 < 0) then
    AZ := AZ + 180;
  if (AZ < 0) then
    AZ := AZ + 360;
  if (AZ > 360) then
    AZ := AZ - 360;
  Str(AZ: 4: 1, num);
  st := st + ', азимут ' + num;
end;
 
procedure TSun.OutInform;
begin
 
  if (M8 = 0) and (W8 = 0) then
  begin
    if V2 < 0 then
      ListBox.Items.Add('Солнце заходит весь день ');
    if V2 > 0 then
      ListBox.Items.Add('Солнце восходит весь день ');
  end
  else
  begin
    if M8 = 0 then
      ListBox.Items.Add('В этот день солнце не восходит ');
    if W8 = 0 then
      ListBox.Items.Add('В этот день солнце не заходит ');
  end;
end;
 
procedure TSun.GetDate;
begin
 
  D := StrToInt(EditD.text);
  M := StrToInt(EditM.text);
  Y := StrToInt(EditY.text);
end;
 
procedure TSun.GetInput;
begin
 
  B5 := StrToInt(EditB5.Text);
  L5 := StrToInt(EditL5.Text);
  H := StrToInt(EditH.Text);
end;
 
procedure TSun.ButtonCalcClick(Sender: TObject);
var
  C0: integer;
begin
 
  GetDate;
  GetInput;
  ListBox.Items.Add('Широта: ' + EditB5.Text +
    ' Долгота: ' + EditL5.Text +
    ' Зона: ' + EditH.Text +
    ' Дата: ' + EditD.Text +
    '/' + EditM.Text +
    '/' + EditY.Text);
  L5 := L5 / 360;
  Z0 := H / 24;
  Calendar;
  T := (J - 2451545) + F;
  TT := T / 36525 + 1; // TT - столетия, начиная с 1900.0
  GetTimeZone; // Получение часового пояса
  T := T + Z0;
  PosOfSun; // Получаем положение солнца
  aA[1] := A5;
  aD[1] := D5;
  T := T + 1;
  PosOfSun;
  aA[2] := A5;
  aD[2] := D5;
  if aA[2] < aA[1] then
    aA[2] := aA[2] + P2;
  Z1 := DR * 90.833; // Вычисление зенита
  S := Sin(B5 * DR);
  C := Cos(B5 * DR);
  Z := Cos(Z1);
  M8 := 0;
  W8 := 0;
  A0 := aA[1];
  D0 := aD[1];
  DA := aA[2] - aA[1];
  DD := aD[2] - aD[1];
  for C0 := 0 to 23 do
  begin
    P := (C0 + 1) / 24;
    A2 := aA[1] + P * DA;
    D2 := aD[1] + P * DD;
    PossibleEvents(C0);
    if st <> '' then
      ListBox.Items.Add(st);
    A0 := A2;
    D0 := D2;
    V0 := V2;
  end;
  OutInform;
  ListBox.Items.Add(''); // Разделяем данные
end;
 
procedure TSun.CreateForm(Sender: TObject);
begin
 
  EditD.Text := FormatDateTime('d', Date);
  EditM.Text := FormatDateTime('m', Date);
  EditY.Text := FormatDateTime('yyyy', Date);
end;
 
procedure TSun.ButtonClearClick(Sender: TObject);
begin
  ListBox.Clear;
end;
 
end.

https://delphiworld.narod.ru/

DelphiWorld 6.0