Files
yapetavi/uelecdistclass.pas
2022-10-24 22:07:20 +02:00

395 lines
12 KiB
ObjectPascal

{
********************************************************************************
YaPeTaVi - Yet another Periodic Table Viewer
Copyright (C) 2011 Geoffray Levasseur <geoffray.levasseurbrandin@numericable.fr>.
All rights reserved.
http://www.geoffray-levasseur.org/
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************
Description:
Component displaying electronic distribution and associated tools
}
unit uElecDistClass;
{$mode objfpc}
interface
uses
Classes, SysUtils, ExtCtrls, Controls;
const
ElecDiam = 11;
type
TElecDist = array [1..7] of Byte;
TElectronicCloud = array[1..7, 1..32] of TShape;
TElecDistDisplay = class(TComponent)
private
FElecDist: TElecDist;
FElecConf: string;
FAtomShape: TShape;
FLayer1Shape: TShape;
FLayer2Shape: TShape;
FLayer3Shape: TShape;
FLayer4Shape: TShape;
FLayer5Shape: TShape;
FLayer6Shape: TShape;
FLayer7Shape: TShape;
FElectrons: TElectronicCloud;
FExpandedElecConf: string;
FOwner: TWinControl;
procedure SetElecConf(AConf: string);
procedure GetElecCoord(Layer, Num, Total: Integer; out Top, Left: Integer);
procedure CreateElectron(var Shape: TShape; Top, Left: integer);
public
constructor Create(AOwner: TWinControl); virtual;
property ElecronicConf: string read FElecConf write SetElecConf;
property ExpandedElecConf: string read FExpandedElecConf;
end;
function ExpandElecConf(S: string): string;
function ConvElecConfToDist(Conf: string; out Dist: TElecDist): Boolean;
implementation
uses
uConst, uDebug, Graphics;
//This function is not generic... It only work with the syntax used in YaPeTaVi
function ExpandElecConf(S: string): string;
const
ExtHe = '1s2';
ExtNe = ExtHe + ' 2s2 2p6';
ExtAr = ExtNe + ' 3s2 3p6';
ExtKr = ExtAr + ' 3d10 4s2 4p6';
ExtXe = ExtKr + ' 4d10 5s2 5p6';
ExtRn = ExtXe + ' 4f14 5d10 6s2 6p6';
var
Tmp: string;
begin
PrintLnDbg('Expanding ' + S + '...', vlHigh);
if (S[1] <> '[') and (S[4] <> ']') then
begin
if S[1] <> '1' then //the first layer must be 1s
Result := ''
else
Result := S;
Exit;
end else
begin
if Pos('He', S) = 2 then
Result := ExtHe + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
if Pos('Ne', S) = 2 then
Result := ExtNe + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
if Pos('Ar', S) = 2 then
Result := ExtAr + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
if Pos('Kr', S) = 2 then
Result := ExtKr + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
if Pos('Xe', S) = 2 then
Result := ExtXe + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
if Pos('Rn', S) = 2 then
Result := ExtRn + ' ' + Trim(Copy(S, 5, Length(S) - 4))
else
begin
Result := ''; //trigger a more explicit error (syntax)
PrintLnDbg('Exited ExpandElecConf with syntax error!', vlHigh);
end;
end;
end;
function ConvElecConfToDist(Conf: string; out Dist: TElecDist): Boolean;
var
I: Integer;
Layer: Integer;
procedure InitDist;
var
J: Integer;
begin
for J := 1 to 7 do
Dist[J] := 0;
end;
begin
I := 1;
InitDist;
Conf := ExpandElecConf(Conf);
Result := True;
if Conf = '' then
begin
PrintLnDbg('Error while expanding ElecConf... Aborting!', vlLow);
Result := False;
Exit;
end;
while I <= Length(Conf) do
begin
if Conf[I] <> ' ' then
if Conf[I] in ['1'..'7'] then
begin
Layer := StrToInt(Conf[I]);
Inc(I, 2); //skip the letter as we don't need it for the use we have
if Conf[I] in ['0'..'9'] then
begin
if Conf[I + 1] in ['0'..'9'] then
begin
Dist[Layer] := Dist[Layer] + StrToInt(Copy(Conf, I, 2));
Inc(I, 2);
end else
begin
Dist[Layer] := Dist[Layer] + StrToInt(Conf[I]);
Inc(I);
end;
end else
begin
PrintLnDbg('Malformed electronic configuration "' + Conf +
'" (second check)', vlLow);
InitDist;
Result := False;
Exit;
end;
end else
begin
PrintLnDbg('Malformed electronic configuration "' + Conf +
'" (first check)', vlLow);
InitDist;
Result := False;
Exit;
end
else
Inc(I);
end;
end;
constructor TElecDistDisplay.Create(AOwner: TWinControl);
var
Max: Integer;
begin
FOwner := AOwner;
FElecConf := '';
FExpandedElecConf := '';
//make it square taking the lowest lenth of the owner
if AOwner.Width > AOwner.Height then
Max := AOwner.Height - 45
else
Max := AOwner.Width - 40;
FLayer7Shape := TShape.Create(AOwner);
FLayer7Shape.Shape := stCircle;
FLayer7Shape.Color := clBlack;
FLayer7Shape.Pen.Style := psSolid;
FLayer7Shape.Brush.Style := bsClear;
if AOwner.Width > AOwner.Height then
begin
FLayer7Shape.Left := (AOwner.Width - Max) div 2;
FLayer7Shape.Width := Max;
FLayer7Shape.Top := 30;
FLayer7Shape.Height := Max;
end else
begin
FLayer7Shape.Top := (AOwner.Height - Max) div 2;
FLayer7Shape.Height := Max;
FLayer7Shape.Left := 25;
FLayer7Shape.Width := Max;
end;
FLayer7Shape.Parent := AOwner;
FLayer7Shape.Visible := True;
FLayer6Shape := TShape.Create(AOwner);
FLayer6Shape.Shape := stCircle;
FLayer6Shape.Color := clBlack;
FLayer6Shape.Pen.Style := psSolid;
FLayer6Shape.Brush.Style := bsClear;
FLayer6Shape.Top := FLayer7Shape.Top + 17;
FLayer6Shape.Width := FLayer7Shape.Width - 34;
FLayer6Shape.Left := FLayer7Shape.Left + 17;
FLayer6Shape.Height := FLayer7Shape.Height - 34;
FLayer6Shape.Parent := AOwner;
FLayer6Shape.Visible := True;
FLayer5Shape := TShape.Create(AOwner);
FLayer5Shape.Shape := stCircle;
FLayer5Shape.Color := clBlack;
FLayer5Shape.Pen.Style := psSolid;
FLayer5Shape.Brush.Style := bsClear;
FLayer5Shape.Top := FLayer6Shape.Top + 17;
FLayer5Shape.Width := FLayer6Shape.Width - 34;
FLayer5Shape.Left := FLayer6Shape.Left + 17;
FLayer5Shape.Height := FLayer6Shape.Height - 34;
FLayer5Shape.Parent := AOwner;
FLayer5Shape.Visible := True;
FLayer4Shape := TShape.Create(AOwner);
FLayer4Shape.Shape := stCircle;
FLayer4Shape.Color := clBlack;
FLayer4Shape.Pen.Style := psSolid;
FLayer4Shape.Brush.Style := bsClear;
FLayer4Shape.Top := FLayer5Shape.Top + 17;
FLayer4Shape.Width := FLayer5Shape.Width - 34;
FLayer4Shape.Left := FLayer5Shape.Left + 17;
FLayer4Shape.Height := FLayer5Shape.Height - 34;
FLayer4Shape.Parent := AOwner;
FLayer4Shape.Visible := True;
FLayer3Shape := TShape.Create(AOwner);
FLayer3Shape.Shape := stCircle;
FLayer3Shape.Color := clBlack;
FLayer3Shape.Pen.Style := psSolid;
FLayer3Shape.Brush.Style := bsClear;
FLayer3Shape.Top := FLayer4Shape.Top + 17;
FLayer3Shape.Width := FLayer4Shape.Width - 34;
FLayer3Shape.Left := FLayer4Shape.Left + 17;
FLayer3Shape.Height := FLayer4Shape.Height - 34;
FLayer3Shape.Parent := AOwner;
FLayer3Shape.Visible := True;
FLayer2Shape := TShape.Create(AOwner);
FLayer2Shape.Shape := stCircle;
FLayer2Shape.Color := clBlack;
FLayer2Shape.Pen.Style := psSolid;
FLayer2Shape.Brush.Style := bsClear;
FLayer2Shape.Top := FLayer3Shape.Top + 17;
FLayer2Shape.Width := FLayer3Shape.Width - 34;
FLayer2Shape.Left := FLayer3Shape.Left + 17;
FLayer2Shape.Height := FLayer3Shape.Height - 34;
FLayer2Shape.Parent := AOwner;
FLayer2Shape.Visible := True;
FLayer1Shape := TShape.Create(AOwner);
FLayer1Shape.Shape := stCircle;
FLayer1Shape.Color := clBlack;
FLayer1Shape.Pen.Style := psSolid;
FLayer1Shape.Brush.Style := bsClear;
FLayer1Shape.Top := FLayer2Shape.Top + 17;
FLayer1Shape.Width := FLayer2Shape.Width - 34;
FLayer1Shape.Left := FLayer2Shape.Left + 17;
FLayer1Shape.Height := FLayer2Shape.Height - 34;
FLayer1Shape.Parent := AOwner;
FLayer1Shape.Visible := True;
FAtomShape := TShape.Create(AOwner);
FAtomShape.Shape := stCircle;
FAtomShape.Color := clMaroon;
FAtomShape.Pen.Style := psSolid;
FAtomShape.Pen.Color := clMaroon;
FAtomShape.Brush.Style := bsSolid;
FAtomShape.Brush.Color := clMaroon;
FAtomShape.Top := FLayer1Shape.Top + 20;
FAtomShape.Width := FLayer1Shape.Width - 40;
FAtomShape.Left := FLayer1Shape.Left + 20;
FAtomShape.Height := FLayer1Shape.Height - 40;
FAtomShape.Parent := AOwner;
FAtomShape.Visible := True;
end;
procedure TElecDistDisplay.CreateElectron(var Shape: TShape;
Top, Left: integer);
begin
if Shape = nil then
Shape := TShape.Create(FOwner);
Shape.Top := Top;
Shape.Left := Left;
Shape.Width := ElecDiam;
Shape.Height := ElecDiam;
Shape.Color := clBlue;
Shape.Shape := stCircle;
Shape.Brush.Color := clBlue;
Shape.Brush.Style := bsSolid;
Shape.Pen.Color := clBlue;
Shape.Pen.Style := psSolid;
Shape.Visible := True;
Shape.Parent := FOwner;
end;
procedure TElecDistDisplay.GetElecCoord(Layer, Num, Total: integer;
out Top, Left: integer);
var
Teta: Real;
Shape: TShape;
begin
case Layer of
1: Shape := FLayer1Shape;
2: Shape := FLayer2Shape;
3: Shape := FLayer3Shape;
4: Shape := FLayer4Shape;
5: Shape := FLayer5Shape;
6: Shape := FLayer6Shape;
7: Shape := FLayer7Shape;
end;
Teta := (Pi / 2) + (2 * Pi * Num) / Total; //calc angle
Top := Round((Shape.Width / 2) * - Sin(Teta)) +
Shape.Top + (Shape.Height div 2) - (ElecDiam div 2);
Left := Round((Shape.Width / 2) * Cos(Teta)) +
Shape.Left + (Shape.Width div 2) - (ElecDiam div 2);
end;
procedure TElecDistDisplay.SetElecConf(AConf: string);
var
Layer, I: integer;
EX, EY: integer;
LayerShape: TShape;
begin
for Layer := 1 to 7 do
for I := 1 to 32 do
begin
FElectrons[Layer, I].Free;
FElectrons[Layer, I] := nil;
end;
FElecConf := AConf;
FExpandedElecConf := ExpandElecConf(AConf);
if not ConvElecConfToDist(AConf, FElecDist) then
FElecConf := '';
//Draw it
PrintDbg('Distribution is ', vlHigh);
for I := 1 to 7 do
PrintDbgResult(IntToStr(FElecDist[I]) + ' ', vlHigh);
PrintLnDbg(vlHigh);
for Layer := 1 to 7 do
begin
case Layer of
1: LayerShape := FLayer1Shape;
2: LayerShape := FLayer2Shape;
3: LayerShape := FLayer3Shape;
4: LayerShape := FLayer4Shape;
5: LayerShape := FLayer5Shape;
6: LayerShape := FLayer6Shape;
7: LayerShape := FLayer7Shape;
end;
LayerShape.Visible := FElecDist[Layer] > 0;
if FElecDist[Layer] > 0 then
for I := 1 to FElecDist[Layer] do
begin
GetElecCoord(Layer, I, FElecDist[Layer], EX, EY);
PrintLnDbg('Showing electron ' + IntToStr(I) + ' on layer ' +
IntToStr(Layer) + ' at coord ' + IntToStr(EX) + ', ' + IntToStr(EY),
vlHigh);
CreateElectron(FElectrons[Layer, I], EX, EY);
end;
end;
end;
end.