unit MolDraw;

{ 1999 - 2010 Vitaly P. Solov'ev }
{ Project Name: MolDraw }

{$mode delphi}

interface

uses
 Graphics, Controls, Types, Classes, SysUtils, Dialogs;

const

// MOLECULAR CONSTANTS

  MaxVale   = 5;        //  Dimension of atom valence array
  SumElem   = 103;      //  Sum of elements for periodic table   
  MaxSumMol = 100000;   //  max sum of molecules in SDF file

// END OF MOLECULAR CONSTANTS

type
  TMol2DView = class(TCustomControl)//class(TGraphicControl)

  private

    display_something : Boolean;

    MolFile : TFileName;
    ListMol : TStrings;

    MolArea : Real;          // Molecular Area is Part of Rectangle

    NAtom   : Integer;       // number of atoms in molecule
    NBond   : Integer;       // number of bound in the molecule
    NAtLi   : Integer;
    Chiral  : Byte;
    NStext  : Integer;
    NReaCo  : Integer;
    NReage  : Integer;
    NProdu  : Integer;
    NInMed  : Integer;
    NProLin : Integer;

    XS      : array of Integer;  // Screen coordinates
    YS      : array of Integer;

    // atom part
    errAT   : Boolean;
    SumMols : Integer;
    MolNo   : Integer;

    atomX   : array of Real;  // atom X coordinate
    atomY   : array of Real;  // atom Y coordinate
    atomZ   : array of Real;  // atom Z coordinate
    CENTRx  : Double;         // Decart centre of Mol
    CENTRy  : Double;
    CENTRz  : Double;    
    atomSym : array of String[3];  // atom symbol
    MasDif  : array of ShortInt;
    Charge  : array of ShortInt;   // Charges
    Stereo  : array of Byte;
    Hydrog  : array of Byte;
    SterBox : array of Byte;
    Valence : array of Byte;
    H0      : array of ShortInt;
    ReaType : array of Byte;
    ReaNo   : array of Byte;
    AAMapNo : array of Byte;
    IReFlag : array of Byte;
    EChFlag : array of Byte;

    // connextivity part
    At1     : array of Integer;  // First atom of the bound
    At2     : array of Integer;  // Second atom of the bound
    BondTyp : array of Byte;     // Bound order
    BStereo : array of Byte;     // Bound stereo type
    BTopol  : array of Byte;
    ReaCent : array of ShortInt;

    // empirical formula
    ValeRow : array of array of Byte;
    SceVale : array of Byte;  // Sceleton nonhydrogen atom valence
    Period  : array of Byte;  // Mendeleev's Table Perion No for atom
    AW      : array of Real;  // Atomic weight

    SumEmpi : Byte;                            // Number of atoms in empirical formula
    AtomEmp : array[1..SumElem] of String[2];  // Atoms of empirical formula
    CoefEmp : array[1..SumElem] of Integer;    // Stoicheometric coef.in empirical formula
    NamEmpi : String[255];                     // String for empirical formula
    MW      : Real;                            // Ralative Molecular Mass

    MolStartLine : array[1..MaxSumMol+1] of Integer;

    // constants for converting of real coodinates to Screen coordinates:
    SLOPE           : Real;
    xICEPT, yICEPT  : Real;
    R               : TRect;

    DrawStyle       : Byte;                       // draw style for 2D structure
    DTSpace         : Byte;                       // double/triple bond spacing
    SBWidth         : Byte;                       // stereo bond width
    AtomColor       : Boolean;                    // color for atoms
    FontSizeForAtom : Integer;                    // font size for atom draw
    FontNameForAtom : string;                     // font name for atom draw

    procedure ReadMol2(MolNo : Integer);
    procedure GetSumOfMols;
    procedure ReadMol();
    procedure MoleculeDraw(Sender: TObject);
    procedure MolCentre;
    procedure MinMax_XY (var a, b : array of Real; l, u : Integer; var a_l, a_h, b_l, b_h : Real);
    procedure ToScale;
    procedure BondDraw(Sender: TObject);
    procedure DrawAtoms(Sender: TObject);
    procedure ChargeDraw(Sender: TObject; indH : Byte; ci : integer);
    procedure HydrogDraw(Sender: TObject; hi : integer);
    procedure NumAttaHydr;
    procedure PrepEmpiFormula;
    procedure EmpiFormDraw(Sender: TObject);

    // Component functions
    procedure set_terminal_groups(b: Boolean);
    function  get_terminal_groups() : Boolean;

  protected
    procedure Paint; override;

  public
    constructor Create(aOwner: TComponent); override;
    destructor  Destroy(); override;
    procedure   LoadFromFile(FileName: TFileName);
    procedure   LoadSDFile(FileName: TFileName);
    procedure   ShowMOL(MolNo : Integer);
    procedure   LoadFromList(_ListMol: TStrings);
    procedure   ClearArea;

  published
    property Align;
    property OnClick;
    property Visible;
    property Anchors;

    property ColorAtoms       : Boolean Read AtomColor Write AtomColor;
    property TerminalGroups   : Boolean Read get_terminal_groups Write set_terminal_groups;
    property DoubleBoundSpace : Byte Read DTSpace Write DTSpace;
    property StereoBoundWidth : Byte Read SBWidth Write SBWidth;
    property FileName         : TFileName Read MolFile Write LoadFromFile;
    property Lines            : TStrings Read ListMol;
    property TotalMols        : Integer Read SumMols Write SumMols;
    property CurrentMol       : Integer Read MolNo Write MolNo;

 end; // Class TMolDraw

type

{ MOLECULAR TYPES }

  ELEMENT=RECORD                            {  Chemical elements  }
    ES : String[2];                         {  Element symbol  }
    EN : String[12];                        {  Element name  }
    V  : array[1..5] of Byte;               {  Valence  }
    P  : Byte;                              {  Period in Mendeleev Table  }
    AW : Real;                              {  Atom weit  }
  end;

{ END OF MOLECULAR TYPE }

                                   {  Read the information about the elements  }
const
  Elem : array[1..SumElem] of ELEMENT = (
    (ES: 'H' ; EN: 'Hydrogen';    V: (0, 1, 0, 0, 0); P: 1; AW: 1.0079   ),
    (ES: 'He'; EN: 'Helium';      V: (0, 0, 0, 0, 0); P: 0; AW: 4.0026   ),
    (ES: 'Li'; EN: 'Lithium';     V: (0, 1, 0, 0, 0); P: 1; AW: 6.941    ),
    (ES: 'Be'; EN: 'Beryllium';   V: (0, 2, 0, 0, 0); P: 2; AW: 9.0122   ),
    (ES: 'B' ; EN: 'Boron';       V: (0, 3, 0, 0, 0); P: 3; AW: 10.811   ),
    (ES: 'C' ; EN: 'Carbon';      V: (0, 4, 0, 0, 0); P: 4; AW: 12.011   ),
    (ES: 'N' ; EN: 'Nitrogen';    V: (0, 3, 5, 0, 0); P: 5; AW: 14.0067  ),
    (ES: 'O' ; EN: 'Oxygen';      V: (0, 2, 0, 0, 0); P: 6; AW: 15.9994  ),
    (ES: 'F' ; EN: 'Fluorine';    V: (0, 1, 0, 0, 0); P: 7; AW: 18.9984  ),
    (ES: 'Ne'; EN: 'Neon';        V: (0, 0, 0, 0, 0); P: 0; AW: 20.179   ),
    (ES: 'Na'; EN: 'Sodium';      V: (0, 1, 0, 0, 0); P: 1; AW: 22.9898  ),
    (ES: 'Mg'; EN: 'Magnesium';   V: (0, 2, 0, 0, 0); P: 2; AW: 24.305   ),
    (ES: 'Al'; EN: 'Aluminum';    V: (0, 3, 0, 0, 0); P: 3; AW: 26.9815  ),
    (ES: 'Si'; EN: 'Silicon';     V: (0, 4, 0, 0, 0); P: 4; AW: 28.0855  ),
    (ES: 'P' ; EN: 'Phosphorus';  V: (0, 3, 5, 0, 0); P: 5; AW: 30.9738  ),
    (ES: 'S' ; EN: 'Sulfur';      V: (0, 2, 4, 6, 0); P: 6; AW: 32.066   ),
    (ES: 'Cl'; EN: 'Chlorine';    V: (0, 1, 3, 5, 7); P: 7; AW: 35.453   ),
    (ES: 'Ar'; EN: 'Argon';       V: (0, 0, 0, 0, 0); P: 0; AW: 39.948   ),
    (ES: 'K' ; EN: 'Potassium';   V: (0, 1, 0, 0, 0); P: 1; AW: 39.0983  ),
    (ES: 'Ca'; EN: 'Calcium';     V: (0, 2, 0, 0, 0); P: 2; AW: 40.078   ),
    (ES: 'Sc'; EN: 'Scandium';    V: (0, 3, 0, 0, 0); P: 3; AW: 44.9559  ),
    (ES: 'Ti'; EN: 'Titanium';    V: (0, 3, 4, 0, 0); P: 4; AW: 47.88    ),
    (ES: 'V' ; EN: 'Vanadium';    V: (0, 2, 3, 4, 5); P: 5; AW: 50.9415  ),
    (ES: 'Cr'; EN: 'Chromium';    V: (0, 2, 3, 6, 0); P: 6; AW: 51.996   ),
    (ES: 'Mn'; EN: 'Manganese';   V: (0, 2, 3, 4, 6); P: 7; AW: 54.938   ),
    (ES: 'Fe'; EN: 'Iron';        V: (0, 2, 3, 4, 6); P: 8; AW: 55.847   ),
    (ES: 'Co'; EN: 'Cobalt';      V: (0, 2, 3, 0, 0); P: 8; AW: 58.9332  ),
    (ES: 'Ni'; EN: 'Nickel';      V: (0, 2, 3, 0, 0); P: 8; AW: 58.69    ),
    (ES: 'Cu'; EN: 'Copper';      V: (0, 1, 2, 0, 0); P: 1; AW: 63.546   ),
    (ES: 'Zn'; EN: 'Zinc';        V: (0, 2, 0, 0, 0); P: 2; AW: 65.39    ),
    (ES: 'Ga'; EN: 'Gallium';     V: (0, 3, 0, 0, 0); P: 3; AW: 69.723   ),
    (ES: 'Ge'; EN: 'Germanium';   V: (0, 2, 4, 0, 0); P: 4; AW: 72.59    ),
    (ES: 'As'; EN: 'Arsenic';     V: (0, 3, 5, 0, 0); P: 5; AW: 74.9216  ),
    (ES: 'Se'; EN: 'Selenium';    V: (0, 2, 4, 6, 0); P: 6; AW: 78.96    ),
    (ES: 'Br'; EN: 'Bromine';     V: (0, 1, 3, 5, 7); P: 7; AW: 79.904   ),
    (ES: 'Kr'; EN: 'Krypton';     V: (0, 0, 0, 0, 0); P: 0; AW: 83.80    ),
    (ES: 'Rb'; EN: 'Rubidium';    V: (0, 1, 0, 0, 0); P: 1; AW: 85.4678  ),
    (ES: 'Sr'; EN: 'Strontium';   V: (0, 2, 0, 0, 0); P: 2; AW: 87.62    ),
    (ES: 'Y' ; EN: 'Yttrium';     V: (0, 3, 0, 0, 0); P: 3; AW: 88.9059  ),
    (ES: 'Zr'; EN: 'Zirconium';   V: (0, 4, 0, 0, 0); P: 4; AW: 91.224   ),
    (ES: 'Nb'; EN: 'Niobium';     V: (0, 3, 5, 0, 0); P: 5; AW: 92.9064  ),
    (ES: 'Mo'; EN: 'Molybdenum';  V: (0, 3, 4, 5, 6); P: 6; AW: 95.94    ),
    (ES: 'Tc'; EN: 'Technetium';  V: (0, 7, 0, 0, 0); P: 7; AW: 98.9062  ),
    (ES: 'Ru'; EN: 'Ruthenium';   V: (0, 2, 3, 4, 6); P: 8; AW: 101.07   ),
    (ES: 'Rh'; EN: 'Rhodium';     V: (0, 2, 3, 4, 0); P: 8; AW: 102.9055 ),
    (ES: 'Pd'; EN: 'Palladium';   V: (0, 2, 4, 0, 0); P: 8; AW: 106.42   ),
    (ES: 'Ag'; EN: 'Silver';      V: (0, 1, 0, 0, 0); P: 1; AW: 107.868  ),
    (ES: 'Cd'; EN: 'Cadmium';     V: (0, 2, 0, 0, 0); P: 2; AW: 112.41   ),
    (ES: 'In'; EN: 'Indium';      V: (0, 3, 0, 0, 0); P: 3; AW: 114.82   ),
    (ES: 'Sn'; EN: 'Tin';         V: (0, 2, 4, 0, 0); P: 4; AW: 118.710  ),
    (ES: 'Sb'; EN: 'Antimony';    V: (0, 3, 5, 0, 0); P: 5; AW: 121.75   ),
    (ES: 'Te'; EN: 'Tellurium';   V: (0, 2, 4, 6, 0); P: 6; AW: 127.60   ),
    (ES: 'I' ; EN: 'Iodine';      V: (0, 1, 3, 5, 7); P: 7; AW: 126.9045 ),
    (ES: 'Xe'; EN: 'Xenon';       V: (0, 0, 0, 0, 0); P: 0; AW: 131.29   ),
    (ES: 'Cs'; EN: 'Cesium';      V: (0, 1, 0, 0, 0); P: 1; AW: 132.905  ),
    (ES: 'Ba'; EN: 'Barium';      V: (0, 2, 0, 0, 0); P: 2; AW: 137.33   ),
    (ES: 'La'; EN: 'Lanthanum';   V: (0, 3, 0, 0, 0); P: 3; AW: 138.9055 ),
    (ES: 'Ce'; EN: 'Cerium';      V: (0, 3, 4, 0, 0); P: 3; AW: 140.12   ),
    (ES: 'Pr'; EN: 'Praseodymium';V: (0, 3, 4, 0, 0); P: 3; AW: 140.9077 ),
    (ES: 'Nd'; EN: 'Neodymium';   V: (0, 3, 0, 0, 0); P: 3; AW: 144.24   ),
    (ES: 'Pm'; EN: 'Promethium';  V: (0, 3, 0, 0, 0); P: 3; AW: 147.0    ),
    (ES: 'Sm'; EN: 'Samarium';    V: (0, 2, 3, 0, 0); P: 3; AW: 150.36   ),
    (ES: 'Eu'; EN: 'Europium';    V: (0, 2, 3, 0, 0); P: 3; AW: 151.96   ),
    (ES: 'Gd'; EN: 'Gadolinium';  V: (0, 3, 0, 0, 0); P: 3; AW: 157.25   ),
    (ES: 'Tb'; EN: 'Terbium';     V: (0, 3, 4, 0, 0); P: 3; AW: 158.9254 ),
    (ES: 'Dy'; EN: 'Dysprosium';  V: (0, 3, 0, 0, 0); P: 3; AW: 162.50   ),
    (ES: 'Ho'; EN: 'Holmium';     V: (0, 3, 0, 0, 0); P: 3; AW: 164.9304 ),
    (ES: 'Er'; EN: 'Erbium';      V: (0, 3, 0, 0, 0); P: 3; AW: 167.26   ),
    (ES: 'Tm'; EN: 'Thulium';     V: (0, 2, 3, 0, 0); P: 3; AW: 168.9342 ),
    (ES: 'Yb'; EN: 'Ytterbium';   V: (0, 2, 3, 0, 0); P: 3; AW: 173.04   ),
    (ES: 'Lu'; EN: 'Lutetium';    V: (0, 3, 0, 0, 0); P: 3; AW: 174.967  ),
    (ES: 'Hf'; EN: 'Hafnium';     V: (0, 4, 0, 0, 0); P: 4; AW: 178.49   ),
    (ES: 'Ta'; EN: 'Tantalum';    V: (0, 5, 0, 0, 0); P: 5; AW: 180.9479 ),
    (ES: 'W' ; EN: 'Tungsten';    V: (0, 3, 4, 5, 6); P: 6; AW: 183.85   ),
    (ES: 'Re'; EN: 'Rhenium';     V: (0, 2, 4, 6, 7); P: 7; AW: 186.207  ),
    (ES: 'Os'; EN: 'Osmium';      V: (0, 2, 3, 4, 6); P: 8; AW: 190.2    ),
    (ES: 'Ir'; EN: 'Iridium';     V: (0, 2, 3, 4, 6); P: 8; AW: 192.22   ),
    (ES: 'Pt'; EN: 'Platinum';    V: (0, 2, 4, 0, 0); P: 8; AW: 195.08   ),
    (ES: 'Au'; EN: 'Gold';        V: (0, 1, 3, 0, 0); P: 1; AW: 196.9665 ),
    (ES: 'Hg'; EN: 'Mercury';     V: (0, 1, 2, 0, 0); P: 2; AW: 200.59   ),
    (ES: 'Tl'; EN: 'Thallium';    V: (0, 1, 3, 0, 0); P: 3; AW: 204.383  ),
    (ES: 'Pb'; EN: 'Lead';        V: (0, 2, 4, 0, 0); P: 4; AW: 207.2    ),
    (ES: 'Bi'; EN: 'Bismuth';     V: (0, 3, 5, 0, 0); P: 5; AW: 208.9804 ),
    (ES: 'Po'; EN: 'Polonium';    V: (0, 2, 4, 0, 0); P: 6; AW: 209.0    ),
    (ES: 'At'; EN: 'Astatine';    V: (0, 1, 3, 5, 7); P: 7; AW: 210.0    ),
    (ES: 'Rn'; EN: 'Radon';       V: (0, 0, 0, 0, 0); P: 0; AW: 222.0    ),
    (ES: 'Fr'; EN: 'Francium';    V: (0, 1, 0, 0, 0); P: 1; AW: 223.0    ),
    (ES: 'Ra'; EN: 'Radium';      V: (0, 2, 0, 0, 0); P: 2; AW: 226.0254 ),
    (ES: 'Ac'; EN: 'Actinium';    V: (0, 3, 0, 0, 0); P: 3; AW: 227.0    ),
    (ES: 'Th'; EN: 'Thorium';     V: (0, 3, 4, 0, 0); P: 3; AW: 232.0381 ),
    (ES: 'Pa'; EN: 'Protactinium';V: (0, 3, 4, 5, 0); P: 3; AW: 231.03559),
    (ES: 'U' ; EN: 'Uranium';     V: (0, 3, 4, 5, 6); P: 3; AW: 238.0289 ),
    (ES: 'Np'; EN: 'Neptunium';   V: (0, 3, 4, 5, 6); P: 3; AW: 237.0482 ),
    (ES: 'Pu'; EN: 'Plutonium';   V: (0, 3, 4, 5, 6); P: 3; AW: 242.0    ),
    (ES: 'Am'; EN: 'Americium';   V: (0, 3, 4, 5, 6); P: 3; AW: 243.0    ),
    (ES: 'Cm'; EN: 'Curium';      V: (0, 3, 0, 0, 0); P: 3; AW: 247.0    ),
    (ES: 'Bk'; EN: 'Berkelium';   V: (0, 3, 4, 0, 0); P: 3; AW: 247.0    ),
    (ES: 'Cf'; EN: 'Californium'; V: (0, 3, 0, 0, 0); P: 3; AW: 249.0    ),
    (ES: 'Es'; EN: 'Einsteinium'; V: (0, 3, 0, 0, 0); P: 3; AW: 254.0    ),
    (ES: 'Fm'; EN: 'Fermium';     V: (0, 3, 0, 0, 0); P: 3; AW: 253.0    ),
    (ES: 'Md'; EN: 'Mendelevium'; V: (0, 3, 0, 0, 0); P: 3; AW: 256.0    ),
    (ES: 'No'; EN: 'Nobelium';    V: (0, 1, 0, 0, 0); P: 3; AW: 254.0    ),
    (ES: 'Lr'; EN: 'Lawrencium';  V: (0, 1, 0, 0, 0); P: 3; AW: 257.0    ));

implementation


//______________________________________________________________________________
//
//   Create
//______________________________________________________________________________
constructor TMol2DView.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  DecimalSeparator  := '.';
  display_something := FALSE;
  SumMols := 0;
  MolFile   := '';
  ListMol   := TStringList.Create;
  AtomColor := TRUE;
  FontSizeForAtom := 9;
  FontNameForAtom := 'Times New Roman';
  DrawStyle := 1;
  DTSpace   := 3; // double bond space5;
  SBWidth   := 2; // stereo bond
end; // Create


//______________________________________________________________________________
//
//   Destroy
//______________________________________________________________________________
destructor TMol2DView.Destroy();
begin
  ListMol.Free;
  inherited Destroy();
end; // Destroy


//______________________________________________________________________________
//
//  SDFinput2 : using TStringList by input molecular data
//  in MDL or SDF standard format
//  See about MOL- and SDF-Formats in: Dalby A., Nourse J.G., Hounshell W.D.
//  Gushurst A.K.I., Grier D.L., Leland B.A., Laufer J. J.Chem.Inf.Comput.
//  Sci., 1992, V.32, No.3, P.244-255.
//______________________________________________________________________________
procedure TMol2DView.ReadMol2(MolNo : Integer);
const
  Np = 10;
var
  i, j, k : Integer;
  LineNo  : Integer;
  CodeErr : Integer;
  wrd     : string;

begin
  CodeErr := 0;  // fix error in input SDF file
  display_something := FALSE;

//------Line 1 of MOLfile------------------------------------------------------
// Molecule name, as any MOL string Length <= 80
// MolName : String[80];
  LineNo  := MolStartLine[MolNo];
  //ShowMessage('Line no. '+IntToStr(LineNo));

//------Line 2 of MOLfile------------------------------------------------------
//  User's first and last initials (UserI), program name (ProgN), date/time:
//  M/D/Y,H:m (DatTim), dimensional codes (DimCo), scaling factors (ScaI, ScaR),
//  energy (Ene) if modeling program input, internal registry number (RegNo)
//  if input through MDL format:
  Inc(LineNo);

//------Line 3 of MOLfile------------------------------------------------------
// A line for comments. If no comment is entered, a blank line must be present.
  Inc(LineNo);

//------Line 4 of MOLfile : The Counts Line------------------------------------
  Inc(LineNo);
  wrd := Trim(Copy(ListMol[LineNo],1,3));
  if Length(wrd)=0 then
    NAtom := 0
  else
    Val(wrd,NAtom,CodeErr);                         // mumber of atoms
  if CodeErr<>0 then begin
    ShowMessage('Read quantity; error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],4,3));
  if Length(wrd)=0 then
    NBond := 0
  else
    Val(wrd,NBond,CodeErr);                         // mumber of bonds
  if CodeErr<>0 then begin
    ShowMessage('Read quantity; error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  if (ListMol.Count < (4+NAtom+NBond)) then begin
    ShowMessage('Read quantity; error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;  // error

  // set tables
  SetLength(atomX, NAtom+Np);
  SetLength(atomY, NAtom+Np);
  SetLength(atomZ, NAtom+Np);
  SetLength(atomSym, NAtom+Np);
  SetLength(MasDif, NAtom+Np);
  SetLength(Charge, NAtom+Np);
  SetLength(Stereo, NAtom+Np);
  SetLength(Hydrog, NAtom+Np);
  SetLength(SterBox, NBond+Np);
  SetLength(Valence, NBond+Np);
  SetLength(H0, NBond+Np);
  SetLength(ReaType, NBond+Np);
  SetLength(ReaNo, NBond+Np);
  SetLength(AAMapNo, NBond+Np);
  SetLength(IReFlag, NBond+Np);
  SetLength(EChFlag, NBond+Np);

  SetLength(At1, NBond+Np);
  SetLength(At2, NBond+Np);
  SetLength(BondTyp, NBond+Np);
  SetLength(BStereo, NBond+Np);
  SetLength(BTopol, NBond+Np);
  SetLength(ReaCent, NBond+Np);

  SetLength(XS, NAtom+Np);
  SetLength(YS, NAtom+Np);

  SetLength(ValeRow, NAtom+Np, MaxVale);
  SetLength(SceVale, NAtom+Np);
  SetLength(Period, NAtom+Np);
  SetLength(AW, NAtom+Np);  

  wrd := Trim(Copy(ListMol[LineNo],7,3));
  if Length(wrd)=0 then
    NAtLi := 0
  else
    Val(wrd,NAtLi,CodeErr);                         // mumber of atom lists
  if CodeErr<>0 then begin
    ShowMessage('Read atom lists; error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],13,3));
  if Length(wrd)=0 then
    Chiral := 0
  else
    Val(wrd,Chiral,CodeErr);                         // chiral flag
  if CodeErr<>0 then begin
    Chiral := 0;
  end;

  wrd := Trim(Copy(ListMol[LineNo],16,3));
  if Length(wrd)=0 then
    NStext := 0
  else
    Val(wrd,NStext,CodeErr);                         // mumber of stext entries
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],19,3));
  if Length(wrd)=0 then
    NReaCo := 0
  else
    Val(wrd,NReaCo,CodeErr);             // mumber of reaction components + 1
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],22,3));
  if Length(wrd)=0 then
    NReage := 0
  else
    Val(wrd,NReage,CodeErr);             // mumber of reactants
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],25,3));
  if Length(wrd)=0 then
    NProdu := 0
  else
    Val(wrd,NProdu,CodeErr);             // mumber of products
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],28,3));
  if Length(wrd)=0 then
    NInMed := 0
  else
    Val(wrd,NInMed,CodeErr);             // mumber of intermediates
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

  wrd := Trim(Copy(ListMol[LineNo],31,3));
  if Length(wrd)=0 then
    NProLin := 0
  else
    Val(wrd,NProLin,CodeErr);     // mumber of lines of additional properties
  if CodeErr<>0 then begin
    ShowMessage('Read error: Mol. no. '+IntToStr(MolNo));
    Exit;
  end;

//------Lines 5-... of MOLfile : The Atom Block--------------------------------
  for i:=1 to NAtom do begin
    Inc(LineNo);
    wrd := Trim(Copy(ListMol[LineNo],1,10));
    if Length(wrd)=0 then
      atomX[i] := 0.0
    else
      Val(wrd,atomX[i],CodeErr);      // atom coordinate X
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],11,10));
    if Length(wrd)=0 then
      atomY[i] := 0.0
    else
      Val(wrd,atomY[i],CodeErr);      // atom coordinate Y
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],21,10));
    if Length(wrd)=0 then
      atomZ[i] := 0.0
    else
      Val(wrd,atomZ[i],CodeErr);      // atom coordinate Z
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],32,3));
    AtomSym[i]:=wrd;                  // atom symbol

    wrd := Trim(Copy(ListMol[LineNo],35,2));
    if Length(wrd)=0 then
      MasDif[i] := 0
    else
      Val(wrd,MasDif[i],CodeErr);     // 1. mass difference
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],37,3));
    if Length(wrd)=0 then
      Charge[i] := 0
    else
      Val(wrd,Charge[i],CodeErr);     // 2. charge
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],40,3));
    if Length(wrd)=0 then
      Stereo[i] := 0
    else
      Val(wrd,Stereo[i],CodeErr);     // 3. atom stereo parity
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],43,3));
    if Length(wrd)=0 then
      Hydrog[i] := 0
    else
      Val(wrd,Hydrog[i],CodeErr);     // 4. hydrogen count + 1
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;
    if Hydrog[i]=1 then Hydrog[i] := 0; // hydrogen count

    wrd := Trim(Copy(ListMol[LineNo],46,3));
    if Length(wrd)=0 then
      SterBox[i] := 0
    else
      Val(wrd,SterBox[i],CodeErr);    // 5. stereo care box
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],49,3));
    if Length(wrd)=0 then
      Valence[i] := 0
    else
      Val(wrd,Valence[i],CodeErr);    // 6. valence
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],52,3));
    if Length(wrd)=0 then
      H0[i] := 0
    else
      Val(wrd,H0[i],CodeErr);         // 7. H0 designator
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],55,3));
    if Length(wrd)=0 then
      ReaType[i] := 0
    else
      Val(wrd,ReaType[i],CodeErr);    // 8. reaction component type
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],58,3));
    if Length(wrd)=0 then
      ReaNo[i] := 0
    else
      Val(wrd,ReaNo[i],CodeErr);      // 9. reaction component number
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],61,3));
    if Length(wrd)=0 then
      AAMapNo[i] := 0
    else
      Val(wrd,AAMapNo[i],CodeErr);      // 10. atom-atom mapping number
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],64,3));
    if Length(wrd)=0 then
      IReFlag[i] := 0
    else
      Val(wrd,IReFlag[i],CodeErr);      // 11. inversion/retention flag
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],67,3));
    if Length(wrd)=0 then
      EChFlag[i] := 0
    else
      Val(wrd,EChFlag[i],CodeErr);      // 12. exact change flag
    if CodeErr<>0 then begin
      ShowMessage('Read atom; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

//  prepare array of valences for the atom
    errAT := TRUE;
    for j:=1 to MaxVale do ValeRow[i,j] := 0;
    Period[i] := 0;
    for j:=1 to SumElem do begin
      if AtomSym[i]=Elem[j].ES then begin
        errAT := FALSE;
        for k:=1 to MaxVale do ValeRow[i,k] := Elem[j].V[k];
        Period[i] := Elem[j].P;
        AW[i] := Elem[j].AW;
      end;
      if AtomSym[i]=Elem[j].ES then Break;
    end;
  end;  // 1..NAtom

//------Lines of MOLfile : The Bond Block--------------------------------------

  for i:=1 to NBond do begin
    Inc(LineNo);
    wrd := Trim(Copy(ListMol[LineNo],1,3));
    if Length(wrd)=0 then
      At1[i] := 0
    else
      Val(wrd,At1[i],CodeErr);        // first atom number for BOND
    if CodeErr<>0 then begin
      ShowMessage('Read bond; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],4,3));
    if Length(wrd)=0 then
      At2[i] := 0
    else
      Val(wrd,At2[i],CodeErr);        // second atom number for BOND
    if CodeErr<>0 then begin
      ShowMessage('Read bond; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],7,3));
    if Length(wrd)=0 then
      BondTyp[i] := 0
    else
      Val(wrd,BondTyp[i],CodeErr);    // bond type
    if CodeErr<>0 then begin
      ShowMessage('Read bond; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],10,3));
    if Length(wrd)=0 then
      BStereo[i] := 0
    else
      Val(wrd,BStereo[i],CodeErr);    // bond stereo
    if CodeErr<>0 then begin
      ShowMessage('Read bond; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;

    wrd := Trim(Copy(ListMol[LineNo],16,3));
    if Length(wrd)=0 then
      BTopol[i] := 0
    else
      Val(wrd,BTopol[i],CodeErr);     // bond topology
    if CodeErr<>0 then begin
      ShowMessage('Read bond; error: Mol. no. '+IntToStr(MolNo));
      Exit;
    end;
  end;  //  1..NBond

  PrepEmpiFormula;  ///

  display_something := TRUE;
end;  // ReadMol2


//______________________________________________________________________________
//
//   ReadMol
//______________________________________________________________________________
procedure TMol2DView.ReadMol();
const
  Np = 10;
var
  wrd     : string;
  i       : integer;
  N       : integer;
  B       : integer;
  ln      : integer;
  CodeErr : integer;
begin
 CodeErr := 0;
 display_something := FALSE;

 if ListMol.Count < 4 then Exit;

 ln := 2;

  // Comments: lines 1 to 3 (ln = 0,1,2)

  // nbr of atoms
  inc(ln);
  wrd:=trim(Copy(ListMol[ln],1,3));

  if Length(wrd)=0 then
    N := 0
  else
    Val(wrd,N,CodeErr);                         // mumber of atoms
  if CodeErr<>0 then begin
    Showmessage('Erreur');
    Exit;
  end;

  wrd:=trim(Copy(ListMol[ln],4,3));
  if Length(wrd)=0 then
    B := 0
  else
    Val(wrd,B,CodeErr);                         // mumber of bonds
  if CodeErr<>0 then begin
    Showmessage('Erreur');
    Exit;
  end;

  if (ListMol.Count < (4 + N + B)) then begin
    ShowMessage('Input file error');
    Exit;
  end; // error

  // set tables
  NAtom := N;
  SetLength(XS, NAtom+Np);
  SetLength(YS, NAtom+Np);
  SetLength(atomX, NAtom+Np);
  SetLength(atomY, NAtom+Np);
  SetLength(atomZ, NAtom+Np);
  SetLength(atomSym, NAtom+Np);
  SetLength(Charge, NAtom+Np);
  SetLength(Hydrog, NAtom+Np);
  SetLength(Stereo, NAtom+Np);

  NBond:=B;
  SetLength(At1, NBond+Np);
  SetLength(At2, NBond+Np);
  SetLength(BondTyp, NBond+Np);
  SetLength(BStereo, NBond+Np);

  for i:=1 to N do begin
    inc(ln);
    // X
    wrd:=Copy(ListMol[ln],4,7);
    wrd:=trim(wrd);
    atomX[i]:=StrToFloat(wrd);
    // Y
    wrd:=Copy(ListMol[ln],14,7);
    wrd:=trim(wrd);
    atomY[i]:=StrToFloatDef(wrd,0);
    // Z
    wrd:=Copy(ListMol[ln],24,7);
    wrd:=trim(wrd);
    atomZ[i]:=StrToFloatDef(wrd,0);
    // Atom symbole
    wrd:=Copy(ListMol[ln],32,3);
    wrd:=trim(wrd);
    atomSym[i] := wrd;

    // *** CHARGES *** //

    wrd:=Copy(ListMol[ln],37,3);
    wrd:=trim(wrd);
    if Length(wrd)=0 then
      Charge[i]:=0
    else
      Val(wrd,Charge[i],CodeErr);     // charge
    if CodeErr<>0 then begin
      Showmessage('Error'); //
      Exit;
    end;

    wrd:=Copy(ListMol[ln],40,3);
    wrd:=trim(wrd);
    if Length(wrd)=0 then
      Stereo[i]:=0
    else
      Val(wrd,Stereo[i],CodeErr);     // atom stereo parity
    if CodeErr<>0 then begin
      Showmessage('Error'); //
      Exit;
    end;

    wrd:=Copy(ListMol[ln],43,3);
    wrd:=trim(wrd);
    if Length(wrd)=0 then
      Hydrog[i]:=0
    else
      Val(wrd,Hydrog[i],CodeErr);     // hydrogen count + 1
    if CodeErr<>0 then begin
      Showmessage('Error'); //
      Exit;
    end;
    if Hydrog[i]=1 then Hydrog[i]:=0; // hydrogen count
   end; // for

   //Bounds
   for i:=1 to B do
    begin
     inc(ln);
//     LineLabel:=Copy(ListMol[ln],1,32);
     wrd:=Copy(ListMol[ln],1,3);
     wrd:=trim(wrd);
     At1[i] := StrToInt(wrd);

     wrd:=Copy(ListMol[ln],4,3);
     wrd:=trim(wrd);
     At2[i] := StrToInt(wrd);

     wrd:=Copy(ListMol[ln],7,3);
     wrd:=trim(wrd);
     bondTyp[i] := StrToInt(wrd);

     wrd:=Copy(ListMol[ln],10,3);
     wrd:=trim(wrd);
     BStereo[i] := StrToInt(wrd);
   end; // for
 display_something := TRUE;
end;  // ReadMol


//______________________________________________________________________________
//
//   MoleculeDraw
//______________________________________________________________________________
procedure TMol2DView.MoleculeDraw(Sender: TObject);
begin
 R := ClientRect;
 with Sender as TMol2DView, Canvas do begin
   // Calcul scale
   ToScale;
   // Draw bonds
   BondDraw(Self);
   // Draw atoms
   DrawAtoms(Self);
   // empirical formula
   EmpiFormDraw(Self);
  end; // with
end; // MoleculeDraw


//______________________________________________________________________________
//
//  MolCentre: Find Decart centre of MOL
//______________________________________________________________________________
procedure TMol2DView.MolCentre;
var
  i : Integer;
begin
  if NAtom>0 then begin
    CENTRx := 0;
    CENTRy := 0;
    CENTRz := 0;
    for i:=1 to NAtom do begin
      CENTRx := CENTRx + atomX[i];
      CENTRy := CENTRy + atomY[i];
      CENTRz := CENTRz + atomZ[i];
    end;
    CENTRx := CENTRx/NAtom;
    CENTRy := CENTRy/NAtom;
    CENTRz := CENTRz/NAtom;
  end;
end;  // MolCentre


//______________________________________________________________________________
//
//  MinMax_XYZ  -  Min and Max values of arrays a[] and b[]
//______________________________________________________________________________
procedure TMol2DView.MinMax_XY ( var a, b : array of Real; l, u : Integer; var a_l, a_h, b_l, b_h : Real );
var
  i : Integer;
begin
  a_l:= a[l];
  a_h:= a[l];
  b_l:= b[l];
  b_h:= b[l];

  for i:=l to u do begin
    if a[i]<a_l then a_l:=a[i];
    if a[i]>a_h then a_h:=a[i];
    if b[i]<b_l then b_l:=b[i];
    if b[i]>b_h then b_h:=b[i];
  end;
end;  // MinMax_XY


//______________________________________________________________________________
//
//  ToScale: transforming real curtesian coordinates to screen coordinates
//______________________________________________________________________________
procedure TMol2DView.ToScale;
const
  MRG = 0.1;    // Margins are 10% of Rectangle
var
  i : Word;
  Marg, XSmin, XSmax, YSmin, YSmax : Integer;
  xmin, xmax, ymin, ymax : Real;
  fx, fy : Real;
  XSC, YSC, xC, yC : Real;

begin
  // Molecular Area is Part of Rectangle
  if NAtom<1 then begin
    MolArea := 0.05;
  end else begin
    MolArea := 0.9; // 0.95;
  end;

  if R.Bottom<=R.Right then Marg := R.Bottom else Marg := R.Right;
  Marg := Round(MRG*MolArea*Marg);
  if Marg<20 then Marg := 20;
  XSmin := Round(R.Left  +Marg);
  XSmax := Round(MolArea*R.Right -Marg);
  YSmin := Round(R.Top   +Marg);
  YSmax := Round(MolArea*R.Bottom-Marg);

  // min and max values of arrays atomX[] and atomY[]
  MinMax_XY ( atomX, atomY, 1, NAtom, xmin, xmax, ymin, ymax );

  if xmax<>xmin then fx:=(XSmax-XSmin)/(xmax-xmin) else fx:=XSmax-XSmin;
  if ymax<>ymin then fy:=(YSmax-YSmin)/(ymax-ymin) else fy:=YSmax-YSmin;
  if fx<=fy then SLOPE:=fx else SLOPE:=fy;
  xC  := 0.5*(xmin+xmax);
  yC  := 0.5*(ymin+ymax);
  XSC := 0.5*(XSmin+XSmax);
  YSC := 0.5*(YSmin+YSmax);
  xICEPT := XSC-SLOPE*xC;
  yICEPT := YSC-SLOPE*yC;

  for i:=1 to NAtom do begin
    XS[i] := Round(SLOPE*atomX[i]+xICEPT);           // XS: Sreen coordinate
    YS[i] := YSmax+Marg-Round(SLOPE*atomY[i]+yICEPT);
  end;
end; // ToScale


//______________________________________________________________________________
//
//  BondsDraw : draw chemical bonds in molecule
//______________________________________________________________________________
procedure TMol2DView.BondDraw(Sender: TObject);
var
  i, j, k, n, m : integer;
  i2, j2, iz, jz: integer;
  PendI, PendJ  : integer;
  XS1, YS1, XS2, YS2: Integer;
  sumR, sumL    : Byte;
  rr, zz        : Real;
  midX, midY, z : Integer;
  DL, DX, DY    : ShortInt;
  P             : Array[1..3] of TPoint;
  BondColor     : TColor;
  BondColor2    : TColor;
  FW, FH        : Integer;

  XB1, YB1      : Integer;
  XB2, YB2      : Integer;  


//______________________________________________________________________________
//
// BondScale in BondsDraw
//______________________________________________________________________________
  procedure BondScale;
  begin
    midX := Round((XS1+XS2)/2);
    midY := Round((YS1+YS2)/2);
    XS1:= XS1-midX;
    XS2:= XS2-midX;
    YS1:= YS1-midY;
    YS2:= YS2-midY;
    zz := 0.8;
    XS1:= Round(XS1*zz);
    XS2:= Round(XS2*zz);
    YS1:= Round(YS1*zz);
    YS2:= Round(YS2*zz);
    XS1:= XS1+midX;
    XS2:= XS2+midX;
    YS1:= YS1+midY;
    YS2:= YS2+midY;
  end;  // BondScale in BondsDraw


//______________________________________________________________________________
//
// MadeSBond in BondsDraw
//______________________________________________________________________________
  procedure MadeSBond(XM1, YM1, XM2, YM2 : Integer);
  begin
    with Sender as TMol2DView, Canvas do begin
      Pen.Color := clGreen;
      Pen.Width := 3;

      XB1 := Round((XM1+2*XM2)/3);
      YB1 := Round((YM1+2*YM2)/3);
      XB2 := Round((2*XM1+XM2)/3);
      YB2 := Round((2*YM1+YM2)/3);

      MoveTo(XB1, YB1);
      LineTo(XB2, YB2);
      Pen.Color := BondColor;
      Pen.Width := 1;
    end;
  end;  // MadeSBond


//______________________________________________________________________________
//
// BrokenSBond in BondsDraw
//______________________________________________________________________________
  procedure BrokenSBond(XM1, YM1, XM2, YM2 : Integer);
  var
    DM : Integer;
  begin
    with Sender as TMol2DView, Canvas do begin
      Pen.Color := clRed;
      Pen.Width := 3;
      DM := DTSpace-1;
      if (k=31) or (k=32) then DM := DTSpace-2;

      XB1 := Round((XM1+XM2)/2);
      YB1 := Round((YM1+YM2)/2);

      if YM1=YM2 then begin
        MoveTo(XB1, YB1);
        LineTo(XB1, YB1+DM);
        MoveTo(XB1, YB1);
        LineTo(XB1, YB1-DM);
      end;
      if XM1=XM2 then begin
        MoveTo(XB1, YB1);
        LineTo(XB1+DM, YB1);
        MoveTo(XB1, YB1);
        LineTo(XB1-DM, YB1);
      end;

      if (XM1<>XM2) and (YM1<>YM2) then begin
        DM := DTSpace;
        if (k=31) or (k=32) then DM := DTSpace-2;
        rr := (YM1-YM2)/(XM1-XM2);
        rr  := -1.0/rr;
        if Abs(rr)>1 then begin
          MoveTo(XB1, YB1);
          LineTo(XB1, YB1+DM);
          MoveTo(XB1, YB1);
          LineTo(XB1, YB1-DM);
        end else begin
          MoveTo(XB1, YB1);
          LineTo(XB1+DM, YB1);
          MoveTo(XB1, YB1);
          LineTo(XB1-DM, YB1);
        end;
      end;  // XM1<>XM2 & YM1<>YM2
      Pen.Color := BondColor;
      Pen.Width := 1;
    end;
  end;  // BrokenSBond


begin
  with Sender as TMol2DView, Canvas do begin
    BondColor := clBlack;
    BondColor2:= clSilver;
    Pen.Color := BondColor;
    Pen.Width := 1;
    Pen.Mode  := pmCopy;
    DL := DTSpace;
    for n:=1 to NBond do begin
      i := At1[n];
      j := At2[n];

      k := BondTyp[n];
      m := BStereo[n];
      if k=0 then Continue;                     // no bond
      case k of
    1,18,81 : begin                             // single bond
                if BStereo[n]=0 then begin
                  Pen.Style := psSolid;
                  MoveTo(XS[i], YS[i]);
                  LineTo(XS[j], YS[j]);

                  XS1 := XS[i];
                  XS2 := XS[j];
                  YS1 := YS[i];
                  YS2 := YS[j];

                  if k=81 then MadeSBond(XS[i], YS[i], XS[j], YS[j]);  // made single bond

                  if k=18 then BrokenSBond(XS[i], YS[i], XS[j], YS[j]);  // broken single bond

                end else begin                  // stereo up bond
                  case m of
                    1 : begin
                          DL := SBWidth;
                          Pen.Color  := BondColor;
                          Brush.Color:= BondColor;
                          Brush.Style:= bsSolid;
                        end;
                    6 : begin
                          DL := SBWidth;
                          Pen.Color   := BondColor2;
                          Brush.Color := BondColor2;
                        end;
                  end;
                  if YS[i]=YS[j] then begin
                    P[1].X:=XS[i]; P[1].Y:=YS[i];
                    P[2].X:=XS[j]; P[2].Y:=YS[j]+DL;
                    P[3].X:=XS[j]; P[3].Y:=YS[j]-DL;
                    Polygon(P);
                  end;
                  if XS[i]=XS[j] then begin
                    P[1].X:=XS[i];    P[1].Y:=YS[i];
                    P[2].X:=XS[j]+DL; P[2].Y:=YS[j];
                    P[3].X:=XS[j]-DL; P[3].Y:=YS[j];
                    Polygon(P);
                  end;
                  if (XS[i]<>XS[j]) and (YS[i]<>YS[j]) then begin
                    DL := Round(SBWidth/2);
                    rr := (YS[i]-YS[j])/(XS[i]-XS[j]);
                    DX := Round(Abs((DL+0.5)*Sin(ArcTan(rr)))+0.5);
                    DY := Round(Abs((DL+0.5)*Cos(ArcTan(rr)))+0.5);
                    if rr<0 then begin
                      P[1].X:=XS[i];    P[1].Y:=YS[i];
                      P[2].X:=XS[j]+DX; P[2].Y:=YS[j]+DY;
                      P[3].X:=XS[j]-DX; P[3].Y:=YS[j]-DY;
                      Polygon(P);
                    end;
                    if rr>0 then begin
                      P[1].X:=XS[i];    P[1].Y:=YS[i];
                      P[2].X:=XS[j]+DX; P[2].Y:=YS[j]-DY;
                      P[3].X:=XS[j]-DX; P[3].Y:=YS[j]+DY;
                      Polygon(P);
                    end;
                  end;
                  Pen.Color  :=BondColor;
                  Brush.Color:=clWhite;
                  Brush.Style:=bsSolid;
                end;  // stereo up
              end;  // k=1

          5 : begin                             // single bond in cycle
                Pen.Style := psDot;
                MoveTo(XS[i], YS[i]);
                LineTo(XS[j], YS[j]);
              end;  // k=5

      2,4,6,
12,21,28,82 : begin                             // double bond
                DL := DTSpace+1;
                Pen.Style := psSolid;
                if k=6 then Pen.Style := psDot;
                Pen.Color  := BondColor;
                i2 := i;
                j2 := j;
                if (atomX[j2]=atomX[i2]) and (atomY[j2]=atomY[i2]) then begin
                  MessageDlg('Two atoms '+AtomSym[i]+'(no. '+IntToStr(i)+
                             ') and '+AtomSym[j]+'(no. '+IntToStr(j)+') occupy equal position',
                              mtWarning, [mbOk], 0);
                  Exit;
                end;
                sumR  := 0;
                sumL  := 0;
                PendI := 0;
                PendJ := 0;
                for z:=1 to NBond do begin
                  iz := At1[z];
                  jz := At2[z];
                  if iz=i2 then PendI := PendI+1;
                  if jz=i2 then PendI := PendI+1;
                  if iz=j2 then PendJ := PendJ+1;
                  if jz=j2 then PendJ := PendJ+1;
                  if (iz=i2) or (iz=j2) then begin
                    if (jz<>i2) and (jz<>j2) then begin
                      if atomX[j2]=atomX[i2] then begin
                        zz := atomX[jz]-atomX[i2];
                      end else begin
                        zz := atomY[i2]-atomY[jz] + (atomY[j2]-atomY[i2])*(atomX[jz]-atomX[i2])/(atomX[j2]-atomX[i2]);
                      end;
                      if zz>0 then sumR := sumR+1;
                      if zz<0 then sumL := sumL+1;
                    end;
                  end;
                  if (jz=i2) or (jz=j2) then begin
                    if (iz<>i2) and (iz<>j2) then begin
                      if atomX[j2]=atomX[i2] then begin
                        zz := atomX[iz]-atomX[i2];
                      end else begin
                        zz := (atomY[i2]-atomY[iz]) + (atomY[j2]-atomY[i2])*(atomX[iz]-atomX[i2])/(atomX[j2]-atomX[i2]);
                      end;
                      if zz>0 then sumR := sumR+1;
                      if zz<0 then sumL := sumL+1;
                    end;
                  end;
                end;  // z=1..NBond

                if sumR=sumL then begin
                  MolCentre;
                  if atomX[j2]=atomX[i2] then begin
                    zz := CENTRx-atomX[i2];
                  end else begin
                    zz := (atomY[i2]-CENTRy) + (atomY[j2]-atomY[i2])*(CENTRx-atomX[i2])/(atomX[j2]-atomX[i2]);
                  end;
                  if zz>0 then sumR:=sumR+1 else sumR:=sumR-1;
                end;

                if (PendI>1) and (PendJ>1) then begin
                  if YS[i]=YS[j] then begin
                    if sumR>sumL then begin
                      XS1 := XS[i];
                      XS2 := XS[j];
                      YS1 := YS[i]+DL;
                      YS2 := YS[j]+DL;
                    end else begin
                      XS1 := XS[i];
                      XS2 := XS[j];
                      YS1 := YS[i]-DL;
                      YS2 := YS[j]-DL;
                    end;
                  end;  // YS[i]=YS[j]
                  if XS[i]=XS[j] then begin
                    if sumR>sumL then begin
                      XS1 := XS[i]+DL;
                      XS2 := XS[j]+DL;
                      YS1 := YS[i];
                      YS2 := YS[j];
                    end else begin
                      XS1 := XS[i]-DL;
                      XS2 := XS[j]-DL;
                      YS1 := YS[i];
                      YS2 := YS[j];
                    end;
                  end;
                  if (XS[i]<>XS[j]) and (YS[i]<>YS[j]) then begin
                    DL := DTSpace+1;
                    rr := (YS[i]-YS[j])/(XS[i]-XS[j]);
                    DX := Round(Abs((DL-0.5)*Sin(ArcTan(rr)))+0.5);
                    DY := Round(Abs((DL-0.5)*Cos(ArcTan(rr)))+0.5);
                    if rr<0 then begin
                      if sumR>sumL then begin
                        XS1 := XS[i]+DX;
                        XS2 := XS[j]+DX;
                        YS1 := YS[i]+DY;
                        YS2 := YS[j]+DY;
                      end else begin
                        XS1 := XS[i]-DX;
                        XS2 := XS[j]-DX;
                        YS1 := YS[i]-DY;
                        YS2 := YS[j]-DY;
                      end;
                    end else begin
                      if sumL>sumR then begin
                        XS1 := XS[i]+DX;
                        XS2 := XS[j]+DX;
                        YS1 := YS[i]-DY;
                        YS2 := YS[j]-DY;
                      end else begin
                        XS1 := XS[i]-DX;
                        XS2 := XS[j]-DX;
                        YS1 := YS[i]+DY;
                        YS2 := YS[j]+DY;
                      end;
                    end;  // r>0
                  end;  // x[i]<>x[j] & y[i]<>y[j]

                  MoveTo(XS[i], YS[i]);
                  LineTo(XS[j], YS[j]);
                  if k=28 then BrokenSBond(XS[i], YS[i], XS[j], YS[j]);  ///
                  if k=82 then MadeSBond(XS[i], YS[i], XS[j], YS[j]);  ///
                  if k=4 then Pen.Style := psDot;
                  BondScale;
                  MoveTo(XS1, YS1);
                  LineTo(XS2, YS2);
                  if (k=12) or (k=82) then MadeSBond(XS1, YS1, XS2, YS2);  ///
                  if (k=21) or (k=28) then BrokenSBond(XS1, YS1, XS2, YS2);  ///
                  Pen.Style := psSolid;

                end else begin
                  DL := Round(DTSpace/2);
                  if YS[i]=YS[j] then begin
                    MoveTo(XS[i], YS[i]+DL);
                    LineTo(XS[j], YS[j]+DL);
                    if k=28 then BrokenSBond(XS[i], YS[i]+DL, XS[j], YS[j]+DL);  ///
                    if k=82 then MadeSBond(XS[i], YS[i]+DL, XS[j], YS[j]+DL);  ///
                    if k=4 then Pen.Style := psDot;
                    MoveTo(XS[i], YS[i]-DL);
                    LineTo(XS[j], YS[j]-DL);
                    if (k=12) or (k=82) then MadeSBond(XS[i], YS[i]-DL, XS[j], YS[j]-DL);  ///
                    if (k=21) or (k=28) then BrokenSBond(XS[i], YS[i]-DL, XS[j], YS[j]-DL);  ///
                    Pen.Style := psSolid;
                  end;
                  if XS[i]=XS[j] then begin
                    MoveTo(XS[i]-DL, YS[i]);
                    LineTo(XS[j]-DL, YS[j]);
                    if k=28 then BrokenSBond(XS[i]-DL, YS[i], XS[j]-DL, YS[j]);  ///
                    if k=82 then MadeSBond(XS[i]-DL, YS[i], XS[j]-DL, YS[j]);  ///
                    if k=4 then Pen.Style := psDot;
                    MoveTo(XS[i]+DL, YS[i]);
                    LineTo(XS[j]+DL, YS[j]);
                    if (k=12) or (k=82) then MadeSBond(XS[i]+DL, YS[i], XS[j]+DL, YS[j]);  ///
                    if (k=21) or (k=28) then BrokenSBond(XS[i]+DL, YS[i], XS[j]+DL, YS[j]);  ///
                    Pen.Style := psSolid;
                  end;
                  if (XS[i]<>XS[j]) and (YS[i]<>YS[j]) then begin
                    DL := Round(DTSpace/2);
                    rr := (YS[i]-YS[j])/(XS[i]-XS[j]);
                    DX := Round(Abs((DL-0.5)*Sin(ArcTan(rr)))+0.5);
                    DY := Round(Abs((DL-0.5)*Cos(ArcTan(rr)))+0.5);
                    if rr<0 then begin
                      MoveTo(XS[i]-DX, YS[i]-DY);
                      LineTo(XS[j]-DX, YS[j]-DY);
                      if k=28 then BrokenSBond(XS[i]-DX, YS[i]-DY, XS[j]-DX, YS[j]-DY);  ///
                      if k=82 then MadeSBond(XS[i]-DX, YS[i]-DY, XS[j]-DX, YS[j]-DY);  ///
                      if k=4 then Pen.Style := psDot;
                      MoveTo(XS[i]+DX, YS[i]+DY);
                      LineTo(XS[j]+DX, YS[j]+DY);
                      if (k=12) or (k=82) then MadeSBond(XS[i]+DX, YS[i]+DY, XS[j]+DX, YS[j]+DY);  ///
                      if (k=21) or (k=28) then BrokenSBond(XS[i]+DX, YS[i]+DY, XS[j]+DX, YS[j]+DY);  ///
                      Pen.Style := psSolid;
                    end else begin
                      MoveTo(XS[i]+DX, YS[i]-DY);
                      LineTo(XS[j]+DX, YS[j]-DY);
                      if k=28 then BrokenSBond(XS[i]+DX, YS[i]-DY, XS[j]+DX, YS[j]-DY);  ///
                      if k=82 then MadeSBond(XS[i]+DX, YS[i]-DY, XS[j]+DX, YS[j]-DY);  ///
                      if k=4 then Pen.Style := psDot;
                      MoveTo(XS[i]-DX, YS[i]+DY);
                      LineTo(XS[j]-DX, YS[j]+DY);
                      if (k=12) or (k=82) then MadeSBond(XS[i]-DX, YS[i]+DY, XS[j]-DX, YS[j]+DY);  ///
                      if (k=21) or (k=28) then BrokenSBond(XS[i]-DX, YS[i]+DY, XS[j]-DX, YS[j]+DY);  ///
                      Pen.Style := psSolid;
                    end;
                  end;  // x[i]<>x[j] & y[i]<>y[j]
                end;  //  PendI>1 and PendJ>1
              end;  // k=2,4,6

          3,
13,23,31,32 : begin                               // triple bond
              DL := DTSpace;
              Pen.Style := psSolid;
              Pen.Color  := BondColor;
              MoveTo(XS[i], YS[i]);
              LineTo(XS[j], YS[j]);
              if YS[i]=YS[j] then begin
                MoveTo(XS[i], YS[i]+DL);
                LineTo(XS[j], YS[j]+DL);
                if (k=13) or (k=23) then MadeSBond(XS[i], YS[i]+DL, XS[j], YS[j]+DL);  ///
                if (k=31) or (k=32) then BrokenSBond(XS[i], YS[i]+DL, XS[j], YS[j]+DL);  ///
                MoveTo(XS[i], YS[i]-DL);
                LineTo(XS[j], YS[j]-DL);
                if k=13 then MadeSBond(XS[i], YS[i]-DL, XS[j], YS[j]-DL);  ///
                if k=31 then BrokenSBond(XS[i], YS[i]-DL, XS[j], YS[j]-DL);  ///
              end;
              if XS[i]=XS[j] then begin
                MoveTo(XS[i]+DL, YS[i]);
                LineTo(XS[j]+DL, YS[j]);
                if (k=13) or (k=23) then MadeSBond(XS[i]+DL, YS[i], XS[j]+DL, YS[j]);  ///
                if (k=31) or (k=32) then BrokenSBond(XS[i]+DL, YS[i], XS[j]+DL, YS[j]);  ///
                MoveTo(XS[i]-DL, YS[i]);
                LineTo(XS[j]-DL, YS[j]);
                if k=13 then MadeSBond(XS[i]-DL, YS[i], XS[j]-DL, YS[j]);  ///
                if k=31 then BrokenSBond(XS[i]-DL, YS[i], XS[j]-DL, YS[j]);  ///
              end;
              if (XS[i]<>XS[j]) and (YS[i]<>YS[j]) then begin
                DL := Round(DTSpace/2);
                rr := (YS[i]-YS[j])/(XS[i]-XS[j]);
                DX := Round(Abs((DL+0.5)*Sin(ArcTan(rr)))+0.5);
                DY := Round(Abs((DL+0.5)*Cos(ArcTan(rr)))+0.5);
                if rr<0 then begin
                  MoveTo(XS[i]+DX, YS[i]+DY);
                  LineTo(XS[j]+DX, YS[j]+DY);
                  if (k=13) or (k=23) then MadeSBond(XS[i]+DX, YS[i]+DY, XS[j]+DX, YS[j]+DY);  ///
                  if (k=31) or (k=32) then BrokenSBond(XS[i]+DX, YS[i]+DY, XS[j]+DX, YS[j]+DY);  ///
                  MoveTo(XS[i]-DX, YS[i]-DY);
                  LineTo(XS[j]-DX, YS[j]-DY);
                  if k=13 then MadeSBond(XS[i]-DX, YS[i]-DY, XS[j]-DX, YS[j]-DY);  ///
                  if k=31 then BrokenSBond(XS[i]-DX, YS[i]-DY, XS[j]-DX, YS[j]-DY);  ///
                end else begin
                  MoveTo(XS[i]+DX, YS[i]-DY);
                  LineTo(XS[j]+DX, YS[j]-DY);
                  if (k=13) or (k=23) then MadeSBond(XS[i]+DX, YS[i]-DY, XS[j]+DX, YS[j]-DY);  ///
                  if (k=31) or (k=32) then BrokenSBond(XS[i]+DX, YS[i]-DY, XS[j]+DX, YS[j]-DY);  ///
                  MoveTo(XS[i]-DX, YS[i]+DY);
                  LineTo(XS[j]-DX, YS[j]+DY);
                  if k=13 then MadeSBond(XS[i]-DX, YS[i]+DY, XS[j]-DX, YS[j]+DY);  ///
                  if k=31 then BrokenSBond(XS[i]-DX, YS[i]+DY, XS[j]-DX, YS[j]+DY);  ///
                end;
              end;  // x[i]<>x[j] & y[i]<>y[j]
            end;  // k=3

        7 : begin                               // triple bond in cycle
              DL := DTSpace;
              Pen.Style := psDot;
              Pen.Color  := BondColor;
              MoveTo(XS[i], YS[i]);
              LineTo(XS[j], YS[j]);
              if YS[i]=YS[j] then begin
                MoveTo(XS[i], YS[i]+DL);
                LineTo(XS[j], YS[j]+DL);
                MoveTo(XS[i], YS[i]-DL);
                LineTo(XS[j], YS[j]-DL);
              end;
              if XS[i]=XS[j] then begin
                MoveTo(XS[i]+DL, YS[i]);
                LineTo(XS[j]+DL, YS[j]);
                MoveTo(XS[i]-DL, YS[i]);
                LineTo(XS[j]-DL, YS[j]);
              end;
              if (XS[i]<>XS[j]) and (YS[i]<>YS[j]) then begin
                DL := Round(DTSpace/2);
                rr := (YS[i]-YS[j])/(XS[i]-XS[j]);
                DX := Round(Abs((DL+0.5)*Sin(ArcTan(rr)))+0.5);
                DY := Round(Abs((DL+0.5)*Cos(ArcTan(rr)))+0.5);
                if rr<0 then begin
                  MoveTo(XS[i]+DX, YS[i]+DY);
                  LineTo(XS[j]+DX, YS[j]+DY);
                  MoveTo(XS[i]-DX, YS[i]-DY);
                  LineTo(XS[j]-DX, YS[j]-DY);
                end;
                if rr>0 then begin
                  MoveTo(XS[i]+DX, YS[i]-DY);
                  LineTo(XS[j]+DX, YS[j]-DY);
                  MoveTo(XS[i]-DX, YS[i]+DY);
                  LineTo(XS[j]-DX, YS[j]+DY);
                end;
              end;  // x[i]<>x[j] & y[i]<>y[j]
            end;  // k=7

        8 : begin                               // special bond I
              z := Pen.Width;
              Pen.Width := 1;
              Pen.Style := psDashDot;
              Pen.Color := BondColor2;
              MoveTo(XS[i], YS[i]);
              LineTo(XS[j], YS[j]);
              Pen.Width := z;
              Pen.Color := BondColor;
            end;  // k=8
        9 : begin                               // special bond II
              z := Pen.Width;
              Pen.Width := 1;
              Pen.Style := psDashDotDot;
              Pen.Color := BondColor2;
              MoveTo(XS[i], YS[i]);
              LineTo(XS[j], YS[j]);
              Pen.Width := z;
              Pen.Color := BondColor;
            end;  // k=9
      end;
      {
      case rc of 10, 20, 30, 40, 50, 60 :       // reaction center
        begin
          Font.Name   := FontNameForAtom;
          Font.Size   := FontSizeForAtom;
          Font.Style  := [fsItalic];
          Font.Color  := clRed;
          FW := TextWidth('Rx'+IntToStr(Round(RCentr[n]/10)));
          FH := TextHeight('R');
          TextOut(Round(0.5*(XS[i]+XS[j]-FW)), Round(0.5*(YS[i]+YS[j]-FH)),
                 'Rx'+IntToStr(Round(RCentr[n]/10)));
        end;
      end;
      }
    end;  //  n=1...NBond
  end;
end; // BoundDraw


//______________________________________________________________________________
//
//  DrawAtoms:   monochrome draw non-carbon and non-hydrogen molecular
//               atoms only
//______________________________________________________________________________
procedure TMol2DView.DrawAtoms(Sender: TObject);
var
  i        : integer;
  FWH, FHH : integer;
begin
  with Sender as TMol2DView, Canvas do begin
    Font.Name   := FontNameForAtom;
    Font.Size   := FontSizeForAtom;
    if DrawStyle=3 then
      Font.Size := Round(2*FontSizeForAtom/3);
    Font.Style  := [];
    Font.Color  := clBlack;
    FWH := Round(0.33*TextWidth('W'));
    FHH := Round(0.50*TextHeight('H'));
    for i:=1 to NAtom do begin
      if (AtomSym[i]='N' ) or
         (AtomSym[i]='O' ) or
         (AtomSym[i]='S' ) or
         (AtomSym[i]='P' ) or
         (AtomSym[i]='F' ) or
         (AtomSym[i]='Cl') or
         (AtomSym[i]='Br') or
         (AtomSym[i]='I' ) or
         (AtomSym[i]='H' )
      then begin
        Font.Name   := FontNameForAtom;
        Font.Size   := FontSizeForAtom; //9;
        if DrawStyle=3 then
          Font.Size := Round(2*FontSizeForAtom/3); //6;
        Font.Style  := [];
        if AtomColor then begin
          if AtomSym[i]='N'  then Font.Color  := clBlue;
          if AtomSym[i]='O'  then Font.Color  := clRed;
          if AtomSym[i]='S'  then Font.Color  := clOlive;
          if AtomSym[i]='P'  then Font.Color  := clFuchsia;
          if AtomSym[i]='F'  then Font.Color  := clGreen;
          if AtomSym[i]='Cl' then Font.Color  := clGreen;
          if AtomSym[i]='Br' then Font.Color  := clGreen;
          if AtomSym[i]='I'  then Font.Color  := clGreen;
          if AtomSym[i]='H'  then Font.Color  := clTeal;
        end;
        TextOut(XS[i]-FWH, YS[i]-FHH, AtomSym[i]);
        HydrogDraw(Self, i);
      end else begin
        if AtomSym[i]<>'C' then begin
          Font.Name   := FontNameForAtom;
          Font.Size   := FontSizeForAtom;
          if DrawStyle=3 then
            Font.Size := Round(2*FontSizeForAtom/3);
          Font.Style  := [];
          Font.Color  := clBlack;
          TextOut(XS[i]-FWH, YS[i]-FHH, AtomSym[i]);
          ChargeDraw(Self, 0, i);
        end else begin
          if (Charge[i]<>0) or
             (Hydrog[i] =3) or
             (Hydrog[i] =4)
          then begin
            Font.Name   := FontNameForAtom;
            Font.Size   := FontSizeForAtom;
            if DrawStyle=3 then
              Font.Size := Round(2*FontSizeForAtom/3);
            Font.Style  := [];
            Font.Color  := clBlack;
            if DrawStyle=1 then begin
              TextOut(XS[i]-FWH, YS[i]-FHH, AtomSym[i]);
            end;
            HydrogDraw(Self, i);
          end;
        end;
      end;
// Stereo=7 for the mark atom
      if Stereo[i]=7 then begin
        Font.Color  := clRed;
        TextOut(XS[i]+FWH, YS[i]+FWH, '*');
      end;
    end; // i=1..NAtom
  end; // TPainBox, Canvas
end; // DrawAtoms


//______________________________________________________________________________
//
//  ChargeDraw: draw charge of the atom
//______________________________________________________________________________
procedure TMol2DView.ChargeDraw(Sender: TObject; indH : Byte; ci : integer);
var
  cx, cy   : Integer;
  FWH, FHH : Integer;
begin
  if (ci > NAtom) or (ci < 1) then begin
    Showmessage('ERROR: CHARGE DRAW');
    Exit;
  end;
  with Sender as TMol2DView, Canvas do begin
    FWH := Round(0.33*TextWidth('W'));
    FHH := Round(0.50*TextHeight('H'));
    Font.Name   := FontNameForAtom;
    Font.Size   := Round(0.9*FontSizeForAtom);
    if DrawStyle=3 then
      Font.Size := Round(0.5*FontSizeForAtom);
    Font.Style  := [];
    Font.Color  := clBlack;
    case indH of
      0: cx:=XS[ci]-Round(0.5*FWH)+TextWidth(AtomSym[ci]);
      1: cx:=XS[ci]-Round(0.5*FWH)+TextWidth(AtomSym[ci])+Round(TextWidth('H'));
    else
      cx:=XS[ci]-Round(0.5*FWH)+TextWidth(AtomSym[ci]);
    end;
    cy:=YS[ci]-FHH-Round(0.4*TextHeight(AtomSym[ci]));
    case Charge[ci] of
      1 : TextOut(cx, cy, '3+' );
      2 : TextOut(cx, cy, '2+' );
      3 : TextOut(cx, cy, '+'  );
      4 : TextOut(cx, cy, '.'  );
      5 : TextOut(cx, cy, '-'  );
      6 : TextOut(cx, cy, '2-' );
      7 : TextOut(cx, cy, '3-' );
    end;
  end;
end;  //  ChargeDraw


//______________________________________________________________________________
//
//  HydrogDraw: draw hydrogen atoms and charge in this cases
//______________________________________________________________________________
procedure TMol2DView.HydrogDraw(Sender: TObject; hi : integer);
var
  hx, hy, hxi, hyi    : Integer;
  SumBons, Neighbo, j : Integer;
  indH                : Byte;
  FHH                 : Integer;
begin
  SumBons:=0;
  Neighbo:=hi;
  for j:=1 to NBond do begin                  // find pendant atom
    if At1[j]=hi then begin
      SumBons:=SumBons+1;
      Neighbo:=At2[j];
    end;
    if At2[j]=hi then begin
      SumBons:=SumBons+1;
      Neighbo:=At1[j];
    end;
  end;  // j=1...NBond

  with Sender as TMol2DView, Canvas do begin
    FHH := Round(0.50*TextHeight('H'));
    Font.Name   := FontNameForAtom;
    Font.Size   := FontSizeForAtom;
    if DrawStyle=3 then
      Font.Size := Round(2*FontSizeForAtom/3);
    Font.Style  := [];
    Font.Color  := clBlack;

    hx :=XS[hi]+Round(0.69*TextWidth(AtomSym[hi]));
    hy :=YS[hi]-FHH;
    hxi:=hx+Round(0.90*TextWidth('H'))+1;
    hyi:=hy+Round(0.30*TextHeight('H'));
    indH:=1;
    if SumBons=1 then begin                   // left pendant group
      if XS[hi]<XS[Neighbo] then begin
        if Hydrog[hi]>1 then begin
          hx:=XS[hi]-Round(2.30*TextWidth('H'));
          hxi:=hx+Round(0.90*TextWidth('H'))+1;
          hyi:=hy+Round(0.30*TextHeight('H'));
        end else begin
          hx:=XS[hi]-Round(1.60*TextWidth('H'));
        end;
        indH:=0;
      end;
    end;
    if Hydrog[hi]=0 then begin
      indH:=0;
      if Charge[hi]<>0 then ChargeDraw(Self, indH, hi);
    end;
    if Hydrog[hi]>0 then begin
      Font.Name   := FontNameForAtom;
      Font.Size   := FontSizeForAtom;
      if DrawStyle=3 then
        Font.Size := Round(2*FontSizeForAtom/3);
      Font.Style  := [];
      Font.Color  := clBlack;
      if DrawStyle=1 then begin
        TextOut(hx-1, hy, ' ');
        TextOut(hx, hy, 'H');
      end;
      if Charge[hi]<>0 then ChargeDraw(Self, indH, hi);
    end;
    if Hydrog[hi]>1 then begin
      Font.Name   := FontNameForAtom;
      Font.Size   := FontSizeForAtom; 
      if DrawStyle=3 then
        Font.Size := Round(0.6*FontSizeForAtom);
      Font.Style  := [];
      Font.Color  := clBlack;
      if DrawStyle=1 then begin
        TextOut(hxi, hyi, IntToStr(Hydrog[hi]));
      end;
    end;
  end;
end;  // HydrogDraw

//______________________________________________________________________________
//
// NumAttaHydr: calculate the number of attached hydrogens for sceleton atom
//______________________________________________________________________________
procedure TMol2DView.NumAttaHydr;
var
  i, ia, j, k : Integer;
begin
  for i:=1 to NAtom do begin
    Hydrog[i]  := 0;
    SceVale[i] := 0;
    ia := 0;
    for j:=1 to NBond do begin
      if (At1[j]=i) or (At2[j]=i) then begin
        case BondTyp[j] of
    1,18,81 : SceVale[i] := SceVale[i]+1;
          2,
12,21,28,82 : SceVale[i] := SceVale[i]+2;
          3,
13,23,31,32 : SceVale[i] := SceVale[i]+3;
          4 : begin
                SceVale[i] := SceVale[i]+2;
                ia := ia+1;
              end;
          5 : SceVale[i] := SceVale[i]+1;
          6 : SceVale[i] := SceVale[i]+2;
          7 : SceVale[i] := SceVale[i]+3;
          8 : SceVale[i] := SceVale[i]+1;
          9 : SceVale[i] := SceVale[i]+0;
        end;
      end;
    end;  // j=1...NBond
    if ia=2 then begin
     SceVale[i] := SceVale[i]-1;
     if (AtomSym[i]='N') and (SceVale[i]=4) and (Charge[i]=0) then SceVale[i] := SceVale[i]-1;
     if (AtomSym[i]='S') and (SceVale[i]=3) and (Charge[i]=0) then SceVale[i] := SceVale[i]-1;
    end;
    if AW[i]<41.0 then begin    // if AW is low 41.0 then it adds Hydrogen atoms
      if Charge[i]=0 then begin
        for k:=MaxVale downto 1 do
          if ValeRow[i,k]>=SceVale[i] then
            Hydrog[i] := ValeRow[i,k]-SceVale[i];
        if SceVale[i]=0 then
          Hydrog[i] := ValeRow[i,2];
      end else begin            // if charge is not equal zero...
        case Charge[i] of
          1 : SceVale[i] := SceVale[i]+3;
          2 : SceVale[i] := SceVale[i]+2;
          3 : SceVale[i] := SceVale[i]+1;
          4 : SceVale[i] := SceVale[i]+1;
          5 : SceVale[i] := SceVale[i]+1;
          6 : SceVale[i] := SceVale[i]+2;
          7 : SceVale[i] := SceVale[i]+3;
        end;
        if Charge[i]<=4 then begin
          if Period[i]<=4 then begin
            for k:=MaxVale downto 1 do
              if ValeRow[i,k]>=SceVale[i] then
                Hydrog[i] := ValeRow[i,k]-SceVale[i];
          end else begin
            for k:=1 to MaxVale do
              if ValeRow[i,k]>=SceVale[i] then
                Hydrog[i] := ValeRow[i,k]-SceVale[i];
          end;
        end else begin
          if Period[i]<4 then begin
            for k:=1 to MaxVale do
              if ValeRow[i,k]>=SceVale[i] then
                Hydrog[i] := ValeRow[i,k]-SceVale[i];
          end else begin
            for k:=MaxVale downto 1 do
              if ValeRow[i,k]>=SceVale[i] then
                Hydrog[i] := ValeRow[i,k]-SceVale[i];
          end;
        end;
      end;  // Charge<>0
    end;  // AW<41.0
  end;  // i=1...NAtom
end;  //  NumAttaHydr


//______________________________________________________________________________
//
//  PrepEmpiFormula: calculate molecular empirical formula
//______________________________________________________________________________
procedure TMol2DView.PrepEmpiFormula;
var
  i, j : Integer;
  IND, L, M : Byte;
  TmpCoef: Integer;
  TmpName   : String[255];
begin

  NumAttaHydr;  ///

  IND:=0;
  SumEmpi:=1;
  AtomEmp[1]:=AtomSym[1];
  CoefEmp[1]:=0;
  for i:=1 to NAtom do begin
    for j:=1 to SumEmpi do begin
      if AtomEmp[j]=AtomSym[i] then begin
        IND:=1;
        CoefEmp[j]:=CoefEmp[j]+1;
      end;
    end;
    if IND=0 then begin
      SumEmpi:=SumEmpi+1;
      CoefEmp[SumEmpi]:=1;
      AtomEmp[SumEmpi]:=AtomSym[i];
    end;
    IND:=0;
  end;

  IND:=0;                             //  Hydrogen atom count
  M  :=0;
  for j:=1 to SumEmpi do
    if AtomEmp[j]='H' then begin
      IND:=1;
      M:=j;
    end;
  if IND=1 then
    j:=M
  else begin
    j:=SumEmpi+1;
    SumEmpi:=j;
    AtomEmp[j]:='H';
    CoefEmp[j]:=0;
  end;
  for i:=1 to NAtom do begin
    CoefEmp[j]:=CoefEmp[j]+Hydrog[i];
  end;
  if CoefEmp[j]=0 then SumEmpi:=SumEmpi-1;

  MW:=0.0;                         // Relative molecular mass - molecular weight
  for i:=1 to SumEmpi do begin
    for j:=1 to SumElem do
      if AtomEmp[i]=Elem[j].ES then begin
        MW:=MW+Elem[j].AW*CoefEmp[i];
      end;
  end;

  IND:=1;                          // Place carbon atom on the first position
  for i:=1 to SumEmpi do begin
    if AtomEmp[i]='C' then begin
      TmpName:=AtomEmp[i];
      AtomEmp[i]:=AtomEmp[1];
      AtomEmp[1]:=TmpName;
      TmpCoef:=CoefEmp[i];
      CoefEmp[i]:=CoefEmp[1];
      CoefEmp[1]:=TmpCoef;
      IND:=IND+1;
    end;
    if AtomEmp[i]='H' then begin   // Place hydrogen atom on the second position
      TmpName:=AtomEmp[i];
      AtomEmp[i]:=AtomEmp[2];
      AtomEmp[2]:=TmpName;
      TmpCoef:=CoefEmp[i];
      CoefEmp[i]:=CoefEmp[2];
      CoefEmp[2]:=TmpCoef;
      IND:=IND+1;
    end;
  end;

  for i:=IND to SumEmpi-1 do begin // to sort the rest of the atoms
    L:=i+1;
    M:=i;
    for j:=L to SumEmpi do if (AtomEmp[j]<AtomEmp[M]) then M:=j;
    TmpName:=AtomEmp[i];
    AtomEmp[i]:=AtomEmp[M];
    AtomEmp[M]:=TmpName;
    TmpCoef:=CoefEmp[i];
    CoefEmp[i]:=CoefEmp[M];
    CoefEmp[M]:=TmpCoef;
  end;
end;  // PrepEmpiFormula


//______________________________________________________________________________
//
//  EmpiFormDraw: draw empirical formula and relative molecular mass
//______________________________________________________________________________
procedure TMol2DView.EmpiFormDraw(Sender: TObject);
var
  MWtmp  : Real;
  TmpStr : String[20];
  i      : Integer;

begin
  with Sender as TMol2DView, Canvas do begin
    Font.Name   := FontNameForAtom;
    Font.Size   := FontSizeForAtom;
    Font.Style  := [];
    Font.Color  := clMaroon;
    NamEmpi:=' ';
  for i:=1 to SumEmpi do begin
    TextOut(R.Left+TextWidth(NamEmpi),
      R.Bottom-TextHeight('H')-TextHeight('H') div 2, AtomEmp[i]);
    NamEmpi:=NamEmpi+AtomEmp[i];
    if CoefEmp[i]>1 then begin
      TextOut(R.Left+TextWidth(NamEmpi),
        R.Bottom-TextHeight('H'), IntToStr(CoefEmp[i]));
      NamEmpi:=NamEmpi+IntToStr(CoefEmp[i]);
    end;
  end;
  MWtmp:=1000.0*(MW-Trunc(MW)+1);
  Str(Round(MWtmp), TmpStr);
  TmpStr:=Copy(TmpStr,2,3);
  TextOut(R.Left
    +TextWidth(NamEmpi+'     '),
    R.Bottom-TextHeight('H')-TextHeight('H') div 2,
    'MW '+IntToStr(Trunc(MW))+'.'+TmpStr);
  end; // TPaintBox, Canvas
end;  //  EmpiFormDraw


//  Private component functions
//______________________________________________________________________________
//
//  set_terminal_groups
//______________________________________________________________________________
procedure TMol2DView.set_terminal_groups(b: boolean);
begin
 if b then DrawStyle:=1 else DrawStyle:=2;
end; // set_terminal_groups


//______________________________________________________________________________
//
//   get_terminal_groups
//______________________________________________________________________________
function TMol2DView.get_terminal_groups() : boolean;
begin
 if DrawStyle = 1 then result := true else result := false;
end; // get_terminal_groups


// Protected
//______________________________________________________________________________
//
//   Paint
//______________________________________________________________________________
procedure TMol2DView.Paint;
begin
 if display_something then MoleculeDraw(Self);
end; // Paint


// Public
//______________________________________________________________________________
//
//   LoadFromFile
//______________________________________________________________________________
procedure TMol2DView.LoadFromFile(FileName: TFileName);
begin
 if not FileExists(FileName) then begin
   ClearArea;
   display_something := FALSE;
   Exit;
 end;
 display_something := TRUE;
 MolFile := FileName;
 ListMol.LoadFromFile(MolFile);
 SumMols := 1;
 ReadMol();
 Invalidate; // Demande a Windows de relancer un evenement Paint pour remettre l'image a jour
end; // LoadFromFile


//______________________________________________________________________________
//
//   LoadSDFile
//______________________________________________________________________________
procedure TMol2DView.LoadSDFile(FileName: TFileName);
begin
 if not FileExists(FileName) then begin
   ClearArea;
   display_something := FALSE;
   Exit;
 end;
 MolFile := FileName;
 ListMol.LoadFromFile(MolFile);
 GetSumOfMols;
end;  // LoadSDFile


//______________________________________________________________________________
//
//  GetSumOfMols:  sum of mols in SDF
//______________________________________________________________________________
procedure TMol2DView.GetSumOfMols;
var
  i, L : Integer;
begin
  SumMols := 0;
  MolStartLine[1] := 0;
  L := ListMol.Count-1;
  for i:=0 to L do begin
    if Pos('$$$$', ListMol[i])>0 then begin
      SumMols := SumMols+1;
      if SumMols>MaxSumMol then begin
        MessageDlg('User can load up to '+IntToStr(MaxSumMol)+' mols.', mtInformation, [mbOk], 0);
        SumMols := SumMols-1;
        Break;
      end;
      MolStartLine[SumMols+1]:=i+1;
    end;
  end;
  // ShowMessage('Sum of Mols: '+IntToStr(SumMols));
end;  // GetSumOfMols


//______________________________________________________________________________
//
//   ShowMOL
//______________________________________________________________________________
procedure TMol2DView.ShowMOL(MolNo : Integer);
begin
 if (MolNo<1) or (MolNo>SumMols) then begin
   ClearArea;
   display_something := FALSE;
   Exit;
 end; //
 // ShowMessage('Mol no: '+IntToStr(MolNo));
 ReadMol2(MolNo);
 Invalidate;
end;  // ShowMOL


//______________________________________________________________________________
//
//   LoadFromList
//______________________________________________________________________________
procedure TMol2DView.LoadFromList(_ListMol: TStrings);
begin
 if (_ListMol.Count < 4) then begin  // maybe add more protection conditions here
   ClearArea;
   display_something := false;
   Exit;
 end;
 display_something := true;
 ListMol.Text := _ListMol.Text;
 SumMols := 1;
 ReadMol();
 Invalidate; // Demande a Windows de relancer un evenement Paint pour remettre l'image a jour
end; // LoadFromList


//______________________________________________________________________________
//
//   ClearArea
//______________________________________________________________________________
procedure TMol2DView.ClearArea();
begin
 // Clear the paint box
 Canvas.Brush.Color := clWhite;
 Canvas.FillRect(ClientRect);
end; // ClearArea

end.
