1
/**********************************************************************
2
Copyright (C) 2006 by Geoff Hutchison
4
This file is part of the Open Babel project.
5
For more information, see <http://openbabel.sourceforge.net/>
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation version 2 of the License.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
15
***********************************************************************/
17
#include <openbabel/babelconfig.h>
18
#include <openbabel/xml.h>
21
#pragma warning (disable : 4800)
28
class ChemDrawXMLFormat : public XMLMoleculeFormat
31
ChemDrawXMLFormat(): Order (-1)
33
OBConversion::RegisterFormat("cdxml", this, "chemical/x-cdxml");
34
XMLConversion::RegisterXMLFormat(this, false, "http://www.camsoft.com/xml/cdxml.dtd");
35
XMLConversion::RegisterXMLFormat(this);
37
virtual const char* NamespaceURI()const{return "http://www.cambridgesoft.com/xml/cdxml.dtd";}
38
virtual const char* Description()
41
ChemDraw CDXML format \n \
42
Minimal support of chemical structure information only.\n \
46
virtual const char* GetMIMEType()
47
{ return "chemical/x-cdxml"; };
49
virtual const char* SpecificationURL()
50
{return "http://www.cambridgesoft.com/services/documentation/sdk/chemdraw/cdx/";}
53
virtual unsigned int Flags()
58
virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
59
virtual bool DoElement(const string& name);
60
virtual bool EndElement(const string& name);
62
// EndTag is used so that the stream buffer is is filled with the XML from
63
// complete objects, as far as possible.
64
virtual const char* EndTag(){ return "/fragment>"; };
66
//atoms and bonds might have no content, so EndElement is not always called
67
// that's why we need to ensure that atoms and bonds are really added.
68
void EnsureEndElement(void);
71
OBAtom _tempAtom; //!< A temporary atom as the atom tag is read
72
int Begin, End, Order, Flag; // Data for current bond
73
map <int, int> atoms; // maps chemdraw atom id to openbabel idx.
74
int _offset; // used to ensure that atoms have different ids.
75
double _scale; // current scale
78
////////////////////////////////////////////////////////////////////
80
ChemDrawXMLFormat theChemDrawXMLFormat;
82
////////////////////////////////////////////////////////////////////
84
bool ChemDrawXMLFormat::DoElement(const string& name)
89
//This is the start of the molecule we are extracting and it will
90
//be put into the OBMol* _pmol declared in the parent class.
91
//initialise everything
95
_pmol->SetDimension(2);
101
buf = _pxmlConv->GetAttribute("Type");
104
if (buf != "Unspecified" && buf != "Element")
106
cerr << "CDXML Format: Node type \"" << buf <<
107
"\" is not currently supported." << endl;
108
return false; // FIXME: use as many types as possible
111
_tempAtom.SetAtomicNum(6); // default is carbon
112
buf = _pxmlConv->GetAttribute("id");
114
_tempAtom.SetIdx(atoi(buf.c_str()));
115
buf = _pxmlConv->GetAttribute("Element");
117
_tempAtom.SetAtomicNum(atoi(buf.c_str()));
119
buf = _pxmlConv->GetAttribute("p"); // coords
122
double x = 0., y = 0.;
123
sscanf(buf.c_str(), "%lf %lf", &x, &y);
124
_tempAtom.SetVector(x, y, 0.);
126
buf = _pxmlConv->GetAttribute("Charge");
128
_tempAtom.SetFormalCharge(atoi(buf.c_str()));
133
bool invert_ends = false;
134
Begin = End = Flag = 0;
135
buf = _pxmlConv->GetAttribute("Order");
137
Order = atoi(buf.c_str());
139
Order = 1; //default value
140
buf = _pxmlConv->GetAttribute("Display");
143
if (buf == "WedgeEnd")
146
Flag = OB_WEDGE_BOND;
148
else if (buf == "WedgeBegin")
149
Flag = OB_WEDGE_BOND;
150
else if (buf == "WedgedHashBegin")
155
else if (buf == "Hash" || buf == "WedgedHashEnd")
158
buf = _pxmlConv->GetAttribute("B");
162
End = atoms[atoi(buf.c_str())];
164
Begin = atoms[atoi(buf.c_str())];
166
buf = _pxmlConv->GetAttribute("E");
170
Begin = atoms[atoi(buf.c_str())];
172
End = atoms[atoi(buf.c_str())];
179
bool ChemDrawXMLFormat::EndElement(const string& name)
184
_pmol->AddAtom(_tempAtom);
185
atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms();
190
_pmol->AddBond(Begin, End, Order, Flag);
193
else if(name=="fragment") //this is the end of the molecule we are extracting
198
return false;//means stop parsing
203
void ChemDrawXMLFormat::EnsureEndElement(void)
205
if (_tempAtom.GetAtomicNum() != 0)
207
_pmol->AddAtom(_tempAtom);
208
atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms();
213
_pmol->AddBond(Begin, End, Order, Flag);
218
bool ChemDrawXMLFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
220
static const xmlChar C_MOLECULE[] = "fragment";
221
static const xmlChar C_CDXML[] = "CDXML";
222
static const xmlChar C_BONDLENGTH[] = "BondLength";
223
static const xmlChar C_PAGE[] = "page";
224
static const xmlChar C_ATOM[] = "n";
225
static const xmlChar C_BOND[] = "b";
226
static const xmlChar C_ID[] = "id";
228
static const xmlChar C_CHARGE[] = "Charge";
229
static const xmlChar C_COORDS[] = "p";
230
static const xmlChar C_ELEMENT[] = "Element";
231
static const xmlChar C_ORDER[] = "Order";
232
static const xmlChar C_BEGIN[] = "B";
233
static const xmlChar C_END[] = "E";
234
static const xmlChar C_DISPLAY[] = "Display";
236
_pxmlConv = XMLConversion::GetDerived(pConv,false);
240
OBMol* pmol = dynamic_cast<OBMol*>(pOb);
246
vector<OBBond*>::iterator j;
247
if(_pxmlConv->GetOutputIndex() == 1)
249
xmlTextWriterStartDocument(writer(), NULL, NULL, NULL);
250
xmlTextWriterWriteDTD(writer(), BAD_CAST "CDXML", NULL, BAD_CAST "http://www.camsoft.com/xml/cdxml.dtd", NULL);
251
xmlTextWriterStartElement(writer(), C_CDXML);
252
xmlTextWriterWriteFormatAttribute(writer(), C_BONDLENGTH , "30");
253
xmlTextWriterStartElement(writer(), C_PAGE); // put everything on one page
254
// now guess the average bond size for the first molecule and scale to 30.
258
for (pbond = mol.BeginBond(j);pbond;pbond = mol.NextBond(j))
259
_scale += pbond->GetLength();
260
_scale /= mol.NumBonds();
263
_scale = 1.; // FIXME: what happens if the molecule has no bond?
264
_scale = 30. / _scale;
268
xmlTextWriterStartElement(writer(), C_MOLECULE);
271
vector<OBAtom*>::iterator i;
273
for (patom = mol.BeginAtom(i);patom;patom = mol.NextAtom(i))
275
xmlTextWriterStartElement(writer(), C_ATOM);
277
xmlTextWriterWriteFormatAttribute(writer(), C_ID , "%d", patom->GetIdx() + _offset);
278
xmlTextWriterWriteFormatAttribute(writer(), C_COORDS , "%f %f", patom->GetX() * _scale, patom->GetY() * _scale);
279
n = patom->GetAtomicNum();
282
xmlTextWriterWriteFormatAttribute(writer(), C_ELEMENT , "%d", n);
284
n = patom->GetFormalCharge();
287
xmlTextWriterWriteFormatAttribute(writer(), C_CHARGE , "%d", n);
289
xmlTextWriterEndElement(writer());
292
for (pbond = mol.BeginBond(j);pbond;pbond = mol.NextBond(j))
294
xmlTextWriterStartElement(writer(), C_BOND);
295
patom = pbond->GetBeginAtom();
296
xmlTextWriterWriteFormatAttribute(writer(), C_BEGIN , "%d", patom->GetIdx() + _offset);
297
patom = pbond->GetEndAtom();
298
xmlTextWriterWriteFormatAttribute(writer(), C_END , "%d", patom->GetIdx() + _offset);
302
xmlTextWriterWriteFormatAttribute(writer(), C_ORDER , "%d", n);
304
if (pbond->IsWedge())
305
xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgeBegin");
306
else if (pbond->IsHash())
307
xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgedHashEnd");
308
xmlTextWriterEndElement(writer());
310
_offset += mol.NumAtoms ();
312
xmlTextWriterEndElement(writer());//molecule
314
if(_pxmlConv->IsLast())
316
xmlTextWriterEndDocument(writer()); // page
317
xmlTextWriterEndDocument(writer()); //document