1 /********************************************************************** 2 Copyright (C) 2002-2006 by Dr. Alex M. Clark and Geoffrey Hutchison 3 Some portions Copyright (C) 2004 by Chris Morley 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation version 2 of the License. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 ***********************************************************************/ 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 #include <cstdlib> 22 23 #include <sstream> 24 25 using namespace std; 26 namespace OpenBabel 27 { 28 29 class CRK2DFormat : public OBMoleculeFormat 30 { 31 public: 32 //Register this format type ID CRK2DFormat()33 CRK2DFormat() 34 { 35 OBConversion::RegisterFormat("crk2d", this, "chemical/x-crk2d"); 36 } 37 Description()38 virtual const char* Description() //required 39 { 40 return 41 "Chemical Resource Kit diagram(2D)\n" 42 "No comments yet\n"; 43 }; 44 SpecificationURL()45 virtual const char* SpecificationURL() 46 {return "http://crk.sourceforge.net/";}; //optional 47 GetMIMEType()48 virtual const char* GetMIMEType() 49 { return "chemical/x-crk2d"; }; 50 51 //Flags() can return be any the following combined by | or be omitted if none apply 52 // NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY Flags()53 virtual unsigned int Flags() 54 { 55 return READONEONLY; 56 }; 57 58 //*** This section identical for most OBMol conversions *** 59 //////////////////////////////////////////////////// 60 /// The "API" interface functions 61 virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv); 62 virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv); 63 64 static bool ReadCRK(std::istream &ifs,OBMol &mol,const char *classTag); 65 static void WriteCRK(std::ostream &ofs,OBMol &mol,bool GroupCharges); 66 67 }; 68 69 70 //Make an instance of the format class 71 CRK2DFormat theCRK2DFormat; 72 73 ///////////////////////////////////////////////////////////////// ReadMolecule(OBBase * pOb,OBConversion * pConv)74 bool CRK2DFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) 75 { 76 77 OBMol* pmol = pOb->CastAndClear<OBMol>(); 78 if (pmol == nullptr) 79 return false; 80 81 //Define some references so we can use the old parameter names 82 istream &ifs = *pConv->GetInStream(); 83 OBMol &mol = *pmol; 84 mol.SetTitle( pConv->GetTitle()); //default title is the filename 85 86 char buffer[BUFF_SIZE];//CM extra buffer 87 88 if (!ifs.getline(buffer,BUFF_SIZE)) 89 { 90 obErrorLog.ThrowError(__FUNCTION__, "File is empty!", obError); 91 return(false); 92 } 93 if (!strstr(buffer,"<Property")) 94 { 95 obErrorLog.ThrowError(__FUNCTION__, "Not valid CRK XML", obWarning); 96 return false; 97 } 98 if (!strstr(buffer,"\"DiagramStructure\"")) 99 { 100 obErrorLog.ThrowError(__FUNCTION__,"Not CRK DiagramStructure (2D)", obWarning); 101 return false; 102 } 103 104 mol.SetDimension(2); 105 return ReadCRK(ifs,mol,"Structure2D"); 106 } 107 108 //////////////////////////////////////////////////////////////// 109 WriteMolecule(OBBase * pOb,OBConversion * pConv)110 bool CRK2DFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) 111 { 112 OBMol* pmol = dynamic_cast<OBMol*>(pOb); 113 if (pmol == nullptr) 114 return false; 115 116 //Define some references so we can use the old parameter names 117 ostream &ofs = *pConv->GetOutStream(); 118 OBMol &mol = *pmol; 119 120 ofs << "<Property Type=\"DiagramStructure\">" << endl; 121 ofs << " <Structure2D>" << endl; 122 123 WriteCRK(ofs,mol,true); 124 125 ofs << " </Structure2D>" << endl; 126 ofs << "</Property>" << endl; 127 128 return true; 129 } 130 131 //****************************************************** 132 class CRK3DFormat : public OBMoleculeFormat 133 { 134 public: 135 //Register this format type ID CRK3DFormat()136 CRK3DFormat() 137 { 138 OBConversion::RegisterFormat("crk3d", this, "chemical/x-crk3d"); 139 } 140 Description()141 virtual const char* Description() //required 142 { 143 return 144 "Chemical Resource Kit 3D format\n" 145 "No comments yet\n"; 146 }; 147 SpecificationURL()148 virtual const char* SpecificationURL() 149 {return "http://crk.sourceforge.net/";}; //optional 150 GetMIMEType()151 virtual const char* GetMIMEType() 152 { return "chemical/x-crk3d"; }; 153 154 //Flags() can return be any the following combined by | or be omitted if none apply 155 // NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY Flags()156 virtual unsigned int Flags() 157 { 158 return READONEONLY; 159 }; 160 161 //*** This section identical for most OBMol conversions *** 162 //////////////////////////////////////////////////// 163 /// The "API" interface functions 164 virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv); 165 virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv); 166 }; 167 //*** 168 169 //Make an instance of the format class 170 CRK3DFormat theCRK3DFormat; 171 172 ///////////////////////////////////////////////////////////////// ReadMolecule(OBBase * pOb,OBConversion * pConv)173 bool CRK3DFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) 174 { 175 176 OBMol* pmol = pOb->CastAndClear<OBMol>(); 177 if (pmol == nullptr) 178 return false; 179 180 //Define some references so we can use the old parameter names 181 istream &ifs = *pConv->GetInStream(); 182 OBMol &mol = *pmol; 183 mol.SetTitle( pConv->GetTitle()); //default title is the filename 184 185 char buffer[BUFF_SIZE];//CM extra buffer 186 187 if (!ifs.getline(buffer,BUFF_SIZE)) 188 { 189 obErrorLog.ThrowError(__FUNCTION__, "File is empty!", obError); 190 return(false); 191 } 192 if (!strstr(buffer,"<Property")) 193 { 194 obErrorLog.ThrowError(__FUNCTION__, "Not valid CRK XML", obWarning); 195 return false; 196 } 197 if (!strstr(buffer,"\"ModelStructure\"") && !strstr(buffer,"\"XRayStructure\"")) 198 { 199 obErrorLog.ThrowError(__FUNCTION__,"Not CRK ModelStructure or XRayStructure (3D).", obWarning); 200 return false; 201 } 202 203 return CRK2DFormat::ReadCRK(ifs,mol,"Structure3D"); 204 } 205 206 //////////////////////////////////////////////////////////////// 207 WriteMolecule(OBBase * pOb,OBConversion * pConv)208 bool CRK3DFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) 209 { 210 OBMol* pmol = dynamic_cast<OBMol*>(pOb); 211 if (pmol == nullptr) 212 return false; 213 214 //Define some references so we can use the old parameter names 215 ostream &ofs = *pConv->GetOutStream(); 216 OBMol &mol = *pmol; 217 218 ofs << "<Property Type=\"ModelStructure\">" << endl; 219 ofs << " <Structure3D>" << endl; 220 221 CRK2DFormat::WriteCRK(ofs,mol,true); 222 223 ofs << " </Structure3D>" << endl; 224 ofs << "</Property>" << endl; 225 226 return true; 227 } 228 229 //************************************************************** ReadCRK(std::istream & ifs,OBMol & mol,const char * classTag)230 bool CRK2DFormat::ReadCRK(std::istream &ifs,OBMol &mol,const char *classTag) 231 { 232 bool foundClass=false; 233 234 #define MAX_ATOMS 1000 235 236 int numAtoms=0; 237 int statomID[MAX_ATOMS]; 238 239 #define MAX_BONDS 1000 240 241 int numBonds=0; 242 int stbondFrom[MAX_BONDS],stbondTo[MAX_BONDS],stbondStyle[MAX_BONDS]; 243 double stbondOrder[MAX_BONDS]; 244 245 bool inAtom=false,inBond=false; 246 int atomID,atomNumber; 247 double atomX,atomY,atomZ,atomCharge; 248 int bondFrom,bondTo,bondStyle; 249 double bondOrder = 0.0f; 250 char buffer[BUFF_SIZE];//was global 251 252 mol.BeginModify(); 253 254 while (ifs.getline(buffer,BUFF_SIZE)) 255 { 256 if (strstr(buffer,classTag) && foundClass == false) 257 foundClass=true; 258 else if (strstr(buffer,classTag) && foundClass == true) 259 break; 260 else if (strstr(buffer,"<Atom")) 261 { 262 atomID=0; 263 char *tag=strstr(buffer,"ID=\""); 264 if (tag) 265 atomID=atoi(tag+4); 266 if (atomID>0) 267 { 268 inAtom=true; 269 atomNumber=0; 270 atomX= atomY= atomZ= atomCharge =0.0; 271 } 272 else 273 continue; // atomID <= 0 274 } 275 else if (strstr(buffer,"<Bond")) 276 { 277 inBond=true; 278 bondFrom=bondTo=bondStyle=0; 279 bondOrder=0; 280 } 281 else if (strstr(buffer,"</Atom>")) 282 { 283 if (inAtom && numAtoms<MAX_ATOMS) 284 { 285 OBAtom atm; 286 atm.Clear(); 287 288 statomID[numAtoms++]=atomID; 289 290 atm.SetAtomicNum(atomNumber); 291 atm.SetVector(atomX,atomY,atomZ); 292 atm.SetFormalCharge((int)atomCharge); 293 294 if (!mol.AddAtom(atm)) 295 { 296 obErrorLog.ThrowError(__FUNCTION__, "Unable to add atom.", obWarning); 297 return false; 298 } 299 } 300 inAtom=false; 301 } 302 else if (strstr(buffer,"</Bond>")) 303 { 304 if (inBond && numBonds<MAX_BONDS) 305 { 306 stbondFrom[numBonds]=bondFrom; 307 stbondTo[numBonds]=bondTo; 308 stbondOrder[numBonds]=bondOrder; 309 stbondStyle[numBonds]=bondStyle; 310 numBonds++; 311 } 312 inBond=false; 313 } 314 else 315 { 316 char *tag; 317 if (inAtom) 318 { 319 tag=strstr(buffer,"<X>"); 320 if (tag) 321 atomX=atof(tag+3); 322 tag=strstr(buffer,"<Y>"); 323 if (tag) 324 atomY=atof(tag+3); 325 tag=strstr(buffer,"<Z>"); 326 if (tag) 327 atomZ=atof(tag+3); 328 tag=strstr(buffer,"<Element>"); 329 if (tag) 330 { 331 char element[3]="\0\0"; 332 element[0]=tag[9]; 333 if (tag[10]>='a' && tag[10]<='z') 334 element[1]=tag[10]; 335 atomNumber=OBElements::GetAtomicNum(element); 336 } 337 tag=strstr(buffer,"<Charge>"); 338 if (tag) 339 atomCharge=atof(tag+8); 340 } 341 if (inBond) 342 { 343 tag=strstr(buffer,"<From>"); 344 if (tag) 345 bondFrom=atoi(tag+6); 346 tag=strstr(buffer,"<To>"); 347 if (tag) 348 bondTo=atoi(tag+4); 349 tag=strstr(buffer,"<Order>"); 350 if (tag) 351 bondOrder=atof(tag+7); 352 tag=strstr(buffer,"<Style>"); 353 if (tag) 354 bondStyle=atoi(tag+7); 355 } 356 } 357 } 358 359 for(int n=0;n<numBonds;n++) 360 { 361 int fromIdx=0,toIdx=0; 362 for(int i=0;i<numAtoms;i++) 363 { 364 if (stbondFrom[n]==statomID[i]) 365 fromIdx=i+1; 366 if (stbondTo[n]==statomID[i]) 367 toIdx=i+1; 368 } 369 370 if (fromIdx>0 && toIdx>0) 371 { 372 OBAtom *from=mol.GetAtom(fromIdx),*to=mol.GetAtom(toIdx); 373 374 int order=1; 375 if (stbondOrder[n]==2) 376 order=2; 377 else if (stbondOrder[n]==3) 378 order=3; 379 else if (stbondOrder[n]==1.5) 380 order=5; 381 382 OBBond bnd; 383 bnd.Set(n+1,from,to,order,0); 384 385 if (stbondStyle[n]==1) 386 bnd.SetWedge(); 387 if (stbondStyle[n]==2) 388 bnd.SetHash(); 389 if (stbondOrder[n]==1.5) 390 bnd.SetAromatic(); 391 392 if (!mol.AddBond(bnd)) 393 { 394 obErrorLog.ThrowError(__FUNCTION__, "Unable to add bond.", obWarning); 395 return false; 396 } 397 } 398 else 399 { 400 stringstream errorMsg; 401 errorMsg << "Unassigned bond ID (" << stbondFrom[n] 402 << " " << stbondTo[n] << "), source may be invalid."; 403 obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning); 404 return false; 405 } 406 } 407 408 mol.EndModify(); 409 410 // we likely have an </Property> line to gobble up 411 if (ifs.peek() != EOF && ifs.good()) 412 { 413 ifs.getline(buffer,BUFF_SIZE); 414 if (strstr(buffer, "</Property>") == nullptr) 415 return false; // something messed up 416 } 417 418 return foundClass; 419 } 420 WriteCRK(std::ostream & ofs,OBMol & mol,bool GroupCharges)421 void CRK2DFormat::WriteCRK(std::ostream &ofs,OBMol &mol,bool GroupCharges) 422 { 423 double groupCharge=0; 424 if (GroupCharges) 425 for(unsigned int n=1;n<=mol.NumAtoms();n++) 426 groupCharge+=mol.GetAtom(n)->GetFormalCharge(); 427 428 ofs << " <Group Charge=\"" << groupCharge << "\" Spin=\"0\">" << endl; 429 430 for(unsigned int n=1;n<=mol.NumAtoms();n++) 431 { 432 OBAtom *atm=mol.GetAtom(n); 433 434 int id=atm->GetIdx(),atomnum=atm->GetAtomicNum(); 435 double x=atm->GetX(),y=atm->GetY(),z=atm->GetZ(); 436 const char *element=OBElements::GetSymbol(atomnum); 437 double charge=0; 438 if (!GroupCharges) 439 charge=atm->GetFormalCharge(); 440 441 //ofs << ((int)atm) << endl; 442 443 ofs << " <Atom ID=\"" << id << "\">" << endl; 444 ofs << " <X>" << x << "</X>" << endl; 445 ofs << " <Y>" << y << "</Y>" << endl; 446 ofs << " <Z>" << z << "</Z>" << endl; 447 ofs << " <Element>" << element << "</Element>" << endl; 448 if (charge!=0) 449 ofs << " <Charge>" << charge << "</Charge>" << endl; 450 ofs << " </Atom>" << endl; 451 } 452 453 for(unsigned int m=0;m<mol.NumBonds();m++) 454 { 455 OBBond *bnd=mol.GetBond(m); 456 457 int from=bnd->GetBeginAtom()->GetIdx(),to=bnd->GetEndAtom()->GetIdx(); 458 double order=bnd->GetBondOrder(); 459 if (bnd->IsAromatic()) 460 order=1.5; 461 int style=0; 462 if (bnd->IsHash()) 463 style=1; 464 if (bnd->IsWedge()) 465 style=2; 466 467 ofs << " <Bond>" << endl; 468 ofs << " <From>" << from << "</From>" << endl; 469 ofs << " <To>" << to << "</To>" << endl; 470 ofs << " <Order>" << order << "</Order>" << endl; 471 ofs << " <Style>" << style << "</Style>" << endl; 472 ofs << " </Bond>" << endl; 473 } 474 475 ofs << " </Group>" << endl; 476 } 477 478 } //namespace OpenBabel 479