1 /**********************************************************************
2 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
3 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
4 Some portions Copyright (C) 2004 by Chris Morley
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 ***********************************************************************/
15 #include <openbabel/babelconfig.h>
16 #include <openbabel/obmolecformat.h>
17 #include <openbabel/mol.h>
18 #include <openbabel/atom.h>
19 #include <openbabel/bond.h>
20 #include <openbabel/elements.h>
21 
22 #include <cstdlib>
23 
24 using namespace std;
25 namespace OpenBabel
26 {
27 
28   class ChemDrawFormat : public OBMoleculeFormat
29   {
30   public:
31     //Register this format type ID
ChemDrawFormat()32     ChemDrawFormat()
33     {
34       OBConversion::RegisterFormat("ct",this);
35     }
36 
Description()37     virtual const char* Description() //required
38     {
39       return
40         "ChemDraw Connection Table format\n"
41         "No comments yet\n";
42     };
43 
SpecificationURL()44     virtual const char* SpecificationURL()
45     {return "";}; //optional
46 
47     //Flags() can return be any the following combined by | or be omitted if none apply
48     // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
Flags()49     virtual unsigned int Flags()
50     {
51       return READONEONLY | WRITEONEONLY;
52     };
53 
54     //*** This section identical for most OBMol conversions ***
55     ////////////////////////////////////////////////////
56     /// The "API" interface functions
57     virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
58     virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
59   };
60   //***
61 
62   //Make an instance of the format class
63   ChemDrawFormat theChemDrawFormat;
64 
65   ////////////////////////////////////////////////////////////////
66 
WriteMolecule(OBBase * pOb,OBConversion * pConv)67   bool ChemDrawFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
68   {
69     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
70     if (pmol == nullptr)
71       return false;
72 
73     //Define some references so we can use the old parameter names
74     ostream &ofs = *pConv->GetOutStream();
75     OBMol &mol = *pmol;
76 
77     char buffer[BUFF_SIZE];
78 
79     ofs << mol.GetTitle() << endl;
80     ofs << " " << mol.NumAtoms() << " " << mol.NumBonds() << endl;
81 
82     OBAtom *atom;
83     vector<OBAtom*>::iterator i;
84 
85     for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
86       {
87         snprintf(buffer, BUFF_SIZE, " %9.4f %9.4f    0.0000 %-1s",
88                  atom->x(),
89                  atom->y(),
90                  OBElements::GetSymbol(atom->GetAtomicNum()));
91         ofs << buffer << endl;
92       }
93 
94     OBBond *bond;
95     vector<OBBond*>::iterator j;
96 
97     for(bond = mol.BeginBond(j);bond;bond = mol.NextBond(j))
98       {
99         snprintf(buffer, BUFF_SIZE, "%3d%3d%3d%3d",
100                  bond->GetBeginAtomIdx(),
101                  bond->GetEndAtomIdx(),
102                  bond->GetBondOrder(), bond->GetBondOrder());
103         ofs << buffer << endl;
104       }
105     return(true);
106   }
107 
ReadMolecule(OBBase * pOb,OBConversion * pConv)108   bool ChemDrawFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
109   {
110     OBMol* pmol = pOb->CastAndClear<OBMol>();
111     if (pmol == nullptr)
112       return false;
113 
114     //Define some references so we can use the old parameter names
115     istream &ifs = *pConv->GetInStream();
116     OBMol &mol = *pmol;
117     const char* title = pConv->GetTitle();
118 
119     char buffer[BUFF_SIZE];
120     unsigned int natoms, nbonds;
121     unsigned int bgn, end, order;
122     vector<string> vs;
123     OBAtom *atom;
124     double x, y, z;
125 
126     mol.SetDimension(2);
127     mol.BeginModify();
128 
129     ifs.getline(buffer,BUFF_SIZE);
130     if (strlen(buffer) == 0)
131       mol.SetTitle(buffer);
132     else
133       mol.SetTitle(title);
134 
135     ifs.getline(buffer,BUFF_SIZE);
136     sscanf(buffer," %d %d", &natoms, &nbonds);
137 
138     for (unsigned int i = 1; i <= natoms; i ++)
139       {
140         if (!ifs.getline(buffer,BUFF_SIZE)) return(false);
141         tokenize(vs,buffer);
142         if (vs.size() != 4) return(false);
143         atom = mol.NewAtom();
144 
145         x = atof((char*)vs[0].c_str());
146         y = atof((char*)vs[1].c_str());
147         z = atof((char*)vs[2].c_str());
148 
149         atom->SetVector(x,y,z); //set coordinates
150         atom->SetAtomicNum(OBElements::GetAtomicNum(vs[3].c_str()));
151       }
152 
153     if (nbonds != 0)
154       for (unsigned int i = 0; i < nbonds; i++)
155         {
156           if (!ifs.getline(buffer,BUFF_SIZE)) return(false);
157           tokenize(vs,buffer);
158           if (vs.size() != 4) return(false);
159           if (!sscanf(buffer,"%d%d%d%*d",&bgn,&end,&order)) return (false);
160           mol.AddBond(bgn,end,order);
161         }
162 
163     // clean out remaining blank lines
164     std::streampos ipos;
165     do
166     {
167       ipos = ifs.tellg();
168       ifs.getline(buffer,BUFF_SIZE);
169     }
170     while(strlen(buffer) == 0 && !ifs.eof() );
171     ifs.seekg(ipos);
172 
173     mol.EndModify();
174     return(true);
175   }
176 
177 
178 } //namespace OpenBabel
179