#include <openbabel/babelconfig.h>
#include <openbabel/obmolecformat.h>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/bond.h>
#include <openbabel/obiter.h>
#include <openbabel/elements.h>
#include <openbabel/generic.h>
#include <cstdlib>
using namespace std;
namespace OpenBabel
{
class XSFFormat : public OBMoleculeFormat
{
public:
XSFFormat()
{
OBConversion::RegisterFormat("xsf",this);
OBConversion::RegisterFormat("axsf",this);
}
virtual const char* Description() {
return
"XCrySDen Structure Format\n"
"Read Options e.g. -as\n"
" s Output single bonds only\n"
" b Disable bonding entirely\n\n";
};
virtual const char* SpecificationURL()
{ return "http://www.xcrysden.org/doc/XSF.html/" ;};
virtual unsigned int Flags()
{
return READONEONLY | NOTWRITABLE;
};
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
};
XSFFormat theXSFFormat;
bool XSFFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = pOb->CastAndClear<OBMol>();
if (pmol == nullptr)
return false;
istream &ifs = *pConv->GetInStream();
OBMol &mol = *pmol;
const char* title = pConv->GetTitle();
char buffer[BUFF_SIZE];
string str;
double x,y,z;
OBAtom *atom;
vector3 translationVectors[3];
int numTranslationVectors = 0;
vector<string> vs;
vector<vector3> atomPositions;
bool createdAtoms = false;
int atomicNum;
mol.BeginModify();
while (ifs.getline(buffer, BUFF_SIZE))
{
if (buffer[0] == '#')
continue; if (strstr(buffer, "ATOMS") != nullptr) {
ifs.getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
while (vs.size() >= 4) {
if (!createdAtoms) {
atom = mol.NewAtom();
atomicNum = OBElements::GetAtomicNum(vs[0].c_str());
if (atomicNum == 0) {
atomicNum = atoi(vs[0].c_str());
}
atom->SetAtomicNum(atomicNum);
}
x = atof((char*)vs[1].c_str());
y = atof((char*)vs[2].c_str());
z = atof((char*)vs[3].c_str());
atomPositions.push_back(vector3(x, y, z));
ifs.getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
}
createdAtoms = true; }
else if ( strstr(buffer, "PRIMVEC")
|| strstr(buffer, "CONVVEC") ) {
numTranslationVectors = 0; while (numTranslationVectors < 3 && ifs.getline(buffer,BUFF_SIZE)) {
tokenize(vs,buffer); if (vs.size() < 3) return false; x = atof((char*)vs[0].c_str());
y = atof((char*)vs[1].c_str());
z = atof((char*)vs[2].c_str());
translationVectors[numTranslationVectors++].Set(x, y, z);
}
}
else if (strstr(buffer, "PRIMCOORD") != nullptr) {
ifs.getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
if (vs.size() < 2) return false;
int numAtoms = atoi(vs[0].c_str());
for (int a = 0; a < numAtoms; ++a) {
if (!ifs.getline(buffer,BUFF_SIZE))
break;
tokenize(vs,buffer);
if (vs.size() < 4)
break;
if (!createdAtoms) {
atom = mol.NewAtom();
atomicNum = OBElements::GetAtomicNum(vs[0].c_str());
if (atomicNum == 0) {
atomicNum = atoi(vs[0].c_str());
}
atom->SetAtomicNum(atomicNum);
}
x = atof((char*)vs[1].c_str());
y = atof((char*)vs[2].c_str());
z = atof((char*)vs[3].c_str());
atomPositions.push_back(vector3(x, y, z));
}
}
}
mol.EndModify();
int natom = mol.NumAtoms();
int numConformers = atomPositions.size() / natom;
for (int i = 0; i < numConformers; ++i) {
double *coordinates = new double[natom * 3];
for (int j = 0; j < natom; ++j) {
vector3 currentPosition = atomPositions[i*natom + j];
coordinates[j*3] = currentPosition.x();
coordinates[j*3 + 1] = currentPosition.y();
coordinates[j*3 + 2] = currentPosition.z();
}
mol.AddConformer(coordinates);
}
mol.DeleteConformer(0);
mol.SetConformer(mol.NumConformers() - 1);
if (!pConv->IsOption("b",OBConversion::INOPTIONS))
mol.ConnectTheDots();
if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
mol.PerceiveBondOrders();
mol.SetTitle(title);
if (numTranslationVectors == 3) {
OBUnitCell *uc = new OBUnitCell;
uc->SetOrigin(fileformatInput);
uc->SetData(translationVectors[0],
translationVectors[1],
translationVectors[2]);
mol.SetData(uc);
}
return(true);
}
}