395 lines
12 KiB
ObjectPascal
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.
|
|
|