void ReportFormat::WriteTorsions(ostream &ofs,OBMol &mol) { vector<OBBond*>::iterator bi1,bi2,bi3; OBBond* bond; OBAtom *a,*b,*c,*d; char buffer[BUFF_SIZE]; //loop through all bonds generating torsions for(bond = mol.BeginBond(bi1); bond; bond = mol.NextBond(bi1)) { b = bond->GetBeginAtom(); c = bond->GetEndAtom(); for(a = b->BeginNbrAtom(bi2);a;a = b->NextNbrAtom(bi2)) { if(a == c) continue; for(d = c->BeginNbrAtom(bi3);d;d = c->NextNbrAtom(bi3)) { if(d == b) continue; snprintf(buffer, BUFF_SIZE, "%4d %4d %4d %4d %10.3f", a->GetIdx(), b->GetIdx(),c->GetIdx(),d->GetIdx(), CalcTorsionAngle(a->GetVector(), b->GetVector(), c->GetVector(), d->GetVector())); ofs << buffer << "\n"; } } } }
void OBRotorList::RemoveSymVals(OBMol &mol) { OBGraphSym gs(&mol); vector<unsigned int> sym_classes; gs.GetSymmetry(sym_classes); OBRotor *rotor; vector<OBRotor*>::iterator i; std::set<unsigned int> syms; for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) { OBBond* bond = rotor->GetBond(); OBAtom* end = bond->GetEndAtom(); OBAtom* begin = bond->GetBeginAtom(); int N_fold_symmetry = 1; for (int here=0; here <= 1; ++here) { // Try each side of the bond in turn OBAtom *this_side, *other_side; if (here == 0) { this_side = begin; other_side = end; } else { this_side = end; other_side = begin; } for (int hyb=2; hyb<=3; ++hyb) { // sp2 and sp3 carbons, with explicit Hs if (this_side->GetAtomicNum() == 6 && this_side->GetHyb() == hyb && this_side->GetValence() == (hyb + 1) ) { syms.clear(); FOR_NBORS_OF_ATOM(nbr, this_side) { if ( &(*nbr) == other_side ) continue; syms.insert(sym_classes[nbr->GetIdx() - 1]); } if (syms.size() == 1) // All of the rotated atoms have the same symmetry class N_fold_symmetry *= hyb; } } } if (N_fold_symmetry > 1) { size_t old_size = rotor->Size(); rotor->RemoveSymTorsionValues(N_fold_symmetry); if (!_quiet) { cout << "...." << N_fold_symmetry << "-fold symmetry at rotor between " << begin->GetIdx() << " and " << end->GetIdx(); cout << " - reduced from " << old_size << " to " << rotor->Size() << endl; } } }
static void FindRings(OBMol &mol,vector<int> &path,OBBitVec &avisit, OBBitVec &bvisit, int natom,int depth ) { OBAtom *atom; OBBond *bond; vector<OBBond*>::iterator k; // don't return if all atoms are visited // (For example, some atoms are in multiple rings!) -GRH if (avisit[natom]) { int j = depth-1; bond=mol.GetBond(path[j--]); bond->SetInRing(); while( j >= 0 ) { bond=mol.GetBond(path[j--]); bond->SetInRing(); (bond->GetBeginAtom())->SetInRing(); (bond->GetEndAtom())->SetInRing(); if(bond->GetBeginAtomIdx()==static_cast<unsigned int>(natom) || bond-> GetEndAtomIdx()==static_cast<unsigned int>(natom)) break; } } else { avisit.SetBitOn(natom); atom = mol.GetAtom(natom); for(bond = atom->BeginBond(k);bond;bond=atom->NextBond(k)) if( !bvisit[bond->GetIdx()]) { path[depth] = bond->GetIdx(); bvisit.SetBitOn(bond->GetIdx()); FindRings(mol,path,avisit,bvisit,bond->GetNbrAtomIdx(atom), depth+1); } } }
bool MOL2Format::ReadMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = pOb->CastAndClear<OBMol>(); if(pmol==NULL) return false; //Define some references so we can use the old parameter names istream &ifs = *pConv->GetInStream(); OBMol &mol = *pmol; //Old code follows... bool foundAtomLine = false; char buffer[BUFF_SIZE]; char *comment = NULL; string str,str1; vector<string> vstr; int len; mol.BeginModify(); for (;;) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); if (EQn(buffer,"@<TRIPOS>MOLECULE",17)) break; } int lcount; int natoms,nbonds; for (lcount=0;;lcount++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); if (EQn(buffer,"@<TRIPOS>ATOM",13)) { foundAtomLine = true; break; } if (lcount == 0) { tokenize(vstr,buffer); if (!vstr.empty()) mol.SetTitle(buffer); } else if (lcount == 1) sscanf(buffer,"%d%d",&natoms,&nbonds); else if (lcount == 4) //energy { tokenize(vstr,buffer); if (!vstr.empty() && vstr.size() == 3) if (vstr[0] == "Energy") mol.SetEnergy(atof(vstr[2].c_str())); } else if (lcount == 5) //comment { if ( buffer[0] ) { len = (int) strlen(buffer)+1; // TODO allow better multi-line comments // which don't allow ill-formed data to consume memory // Thanks to Andrew Dalke for the pointer if (comment != NULL) delete [] comment; comment = new char [len]; memcpy(comment,buffer,len); } } } if (!foundAtomLine) { mol.EndModify(); mol.Clear(); obErrorLog.ThrowError(__FUNCTION__, "Unable to read Mol2 format file. No atoms found.", obWarning); return(false); } mol.ReserveAtoms(natoms); int i; vector3 v; OBAtom atom; bool hasPartialCharges=false; double x,y,z,pcharge; char temp_type[BUFF_SIZE], resname[BUFF_SIZE], atmid[BUFF_SIZE]; int elemno, resnum = -1; ttab.SetFromType("SYB"); for (i = 0;i < natoms;i++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); sscanf(buffer," %*s %1024s %lf %lf %lf %1024s %d %1024s %lf", atmid, &x,&y,&z, temp_type, &resnum, resname, &pcharge); atom.SetVector(x, y, z); // Handle "CL" and "BR" and other mis-typed atoms str = temp_type; if (strncmp(temp_type, "CL", 2) == 0) { str = "Cl"; } else if (strncmp(temp_type,"BR",2) == 0) { str = "Br"; } else if (strncmp(temp_type,"S.o2", 4) == 02) { str = "S.O2"; } else if (strncmp(temp_type,"S.o", 3) == 0) { str = "S.O"; } else if (strncmp(temp_type,"SI", 2) == 0) { str = "Si"; // The following cases are entries which are not in openbabel/data/types.txt // and should probably be added there } else if (strncmp(temp_type,"S.1", 3) == 0) { str = "S.2"; // no idea what the best type might be here } else if (strncmp(temp_type,"P.", 2) == 0) { str = "P.3"; } else if (strncasecmp(temp_type,"Ti.", 3) == 0) { // e.g. Ti.th str = "Ti"; } else if (strncasecmp(temp_type,"Ru.", 3) == 0) { // e.g. Ru.oh str = "Ru"; } ttab.SetToType("ATN"); ttab.Translate(str1,str); elemno = atoi(str1.c_str()); ttab.SetToType("IDX"); // We might have missed some SI or FE type things above, so here's // another check if( !elemno && isupper(temp_type[1]) ) { temp_type[1] = (char)tolower(temp_type[1]); str = temp_type; ttab.Translate(str1,str); elemno = atoi(str1.c_str()); } // One last check if there isn't a period in the type, // it's a malformed atom type, but it may be the element symbol // GaussView does this (PR#1739905) if ( !elemno ) { obErrorLog.ThrowError(__FUNCTION__, "This Mol2 file is non-standard. Cannot interpret atom types correctly, instead attempting to interpret as elements instead.", obWarning); string::size_type dotPos = str.find('.'); if (dotPos == string::npos) { elemno = etab.GetAtomicNum(str.c_str()); } } atom.SetAtomicNum(elemno); ttab.SetToType("INT"); ttab.Translate(str1,str); atom.SetType(str1); atom.SetPartialCharge(pcharge); if (!mol.AddAtom(atom)) return(false); if (!IsNearZero(pcharge)) hasPartialCharges = true; // Add residue information if it exists if (resnum != -1 && resnum != 0 && strlen(resname) != 0 && strncmp(resname,"<1>", 3) != 0) { OBResidue *res = (mol.NumResidues() > 0) ? mol.GetResidue(mol.NumResidues()-1) : NULL; if (res == NULL || res->GetName() != resname || static_cast<int>(res->GetNum()) != resnum) { vector<OBResidue*>::iterator ri; for (res = mol.BeginResidue(ri) ; res ; res = mol.NextResidue(ri)) if (res->GetName() == resname && static_cast<int>(res->GetNum()) == resnum) break; if (res == NULL) { res = mol.NewResidue(); res->SetName(resname); res->SetNum(resnum); } } OBAtom *atomPtr = mol.GetAtom(mol.NumAtoms()); res->AddAtom(atomPtr); res->SetAtomID(atomPtr, atmid); } // end adding residue info } for (;;) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); str = buffer; if (!strncmp(buffer,"@<TRIPOS>BOND",13)) break; } int start,end,order; for (i = 0; i < nbonds; i++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); sscanf(buffer,"%*d %d %d %1024s",&start,&end,temp_type); str = temp_type; order = 1; if (str == "ar" || str == "AR" || str == "Ar") order = 5; else if (str == "AM" || str == "am" || str == "Am") order = 1; else order = atoi(str.c_str()); mol.AddBond(start,end,order); } // update neighbour bonds information for each atom. vector<OBAtom*>::iterator apos; vector<OBBond*>::iterator bpos; OBAtom* patom; OBBond* pbond; for (patom = mol.BeginAtom(apos); patom; patom = mol.NextAtom(apos)) { patom->ClearBond(); for (pbond = mol.BeginBond(bpos); pbond; pbond = mol.NextBond(bpos)) { if (patom == pbond->GetBeginAtom() || patom == pbond->GetEndAtom()) { patom->AddBond(pbond); } } } // Suggestion by Liu Zhiguo 2008-01-26 // Mol2 files define atom types -- there is no need to re-perceive mol.SetAtomTypesPerceived(); mol.EndModify(); //must add generic data after end modify - otherwise it will be blown away if (comment) { OBCommentData *cd = new OBCommentData; cd->SetData(comment); cd->SetOrigin(fileformatInput); mol.SetData(cd); delete [] comment; comment = NULL; } if (hasPartialCharges) mol.SetPartialChargesPerceived(); // continue untill EOF or untill next molecule record streampos pos; for(;;) { pos = ifs.tellg(); if (!ifs.getline(buffer,BUFF_SIZE)) break; if (EQn(buffer,"@<TRIPOS>MOLECULE",17)) break; } ifs.seekg(pos); // go back to the end of the molecule return(true); }
bool MOL2Format::WriteMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(pmol==NULL) return false; //Define some references so we can use the old parameter names ostream &ofs = *pConv->GetOutStream(); OBMol &mol = *pmol; bool ligandsOnly = pConv->IsOption("l", OBConversion::OUTOPTIONS)!=NULL; //The old code follows.... string str,str1; char buffer[BUFF_SIZE],label[BUFF_SIZE]; char rnum[BUFF_SIZE],rlabel[BUFF_SIZE]; ofs << "@<TRIPOS>MOLECULE" << endl; str = mol.GetTitle(); if (str.empty()) ofs << "*****" << endl; else ofs << str << endl; snprintf(buffer, BUFF_SIZE," %d %d 0 0 0", mol.NumAtoms(),mol.NumBonds()); ofs << buffer << endl; ofs << "SMALL" << endl; OBPairData *dp = (OBPairData*)mol.GetData("PartialCharges"); if (dp != NULL) { // Tripos spec says: // NO_CHARGES, DEL_RE, GASTEIGER, GAST_HUCK, HUCKEL, PULLMAN, // GAUSS80_CHARGES, AMPAC_CHARGES, MULLIKEN_CHARGES, DICT_ CHARGES, // MMFF94_CHARGES, USER_CHARGES if (dp->GetValue() == "Mulliken") ofs << "MULLIKEN_CHARGES" << endl; else // should pick from the Tripos types ofs << "GASTEIGER" << endl; } else { // No idea what these charges are... all our code sets "PartialCharges" ofs << "GASTEIGER" << endl; } ofs << "Energy = " << mol.GetEnergy() << endl; if (mol.HasData(OBGenericDataType::CommentData)) { OBCommentData *cd = (OBCommentData*)mol.GetData(OBGenericDataType::CommentData); ofs << cd->GetData(); } ofs << endl; ofs << "@<TRIPOS>ATOM" << endl; OBAtom *atom; OBResidue *res; vector<OBAtom*>::iterator i; vector<int> labelcount; labelcount.resize( etab.GetNumberOfElements() ); ttab.SetFromType("INT"); ttab.SetToType("SYB"); for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { // // Use sequentially numbered atom names if no residues // snprintf(label,BUFF_SIZE, "%s%d", etab.GetSymbol(atom->GetAtomicNum()), ++labelcount[atom->GetAtomicNum()]); strcpy(rlabel,"<1>"); strcpy(rnum,"1"); str = atom->GetType(); ttab.Translate(str1,str); // // Use original atom names if there are residues // if (!ligandsOnly && (res = atom->GetResidue()) ) { // use original atom names defined by residue snprintf(label,BUFF_SIZE,"%s",(char*)res->GetAtomID(atom).c_str()); // make sure that residue name includes its number snprintf(rlabel,BUFF_SIZE,"%s%d",res->GetName().c_str(), res->GetNum()); snprintf(rnum,BUFF_SIZE,"%d",res->GetNum()); } snprintf(buffer,BUFF_SIZE,"%7d%1s%-6s%12.4f%10.4f%10.4f%1s%-5s%4s%1s %-8s%10.4f", atom->GetIdx(),"",label, atom->GetX(),atom->GetY(),atom->GetZ(), "",str1.c_str(), rnum,"",rlabel, atom->GetPartialCharge()); ofs << buffer << endl; } ofs << "@<TRIPOS>BOND" << endl; OBBond *bond; vector<OBBond*>::iterator j; OBSmartsPattern pat; string s1, s2; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { s1 = bond->GetBeginAtom()->GetType(); s2 = bond->GetEndAtom()->GetType(); if (bond->IsAromatic() || s1 == "O.co2" || s2 == "O.co2") strcpy(label,"ar"); else if (bond->IsAmide()) strcpy(label,"am"); else snprintf(label,BUFF_SIZE,"%d",bond->GetBO()); snprintf(buffer, BUFF_SIZE,"%6d%6d%6d%3s%2s", bond->GetIdx()+1,bond->GetBeginAtomIdx(),bond->GetEndAtomIdx(), "",label); ofs << buffer << endl; } // NO trailing blank line (PR#1868929). // ofs << endl; return(true); }
bool OBChemTsfm::Apply(OBMol &mol) { if (!_bgn.Match(mol)) return(false); mol.BeginModify(); vector<vector<int> > mlist = _bgn.GetUMapList(); obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::OBChemTransform", obAuditMsg); if (!_vchrg.empty()) //modify charges { vector<vector<int> >::iterator i; vector<pair<int,int> >::iterator j; for (i = mlist.begin();i != mlist.end();++i) for (j = _vchrg.begin();j != _vchrg.end();++j) if (j->first < (signed)i->size()) { //goof proofing OBAtom *atom = mol.GetAtom((*i)[j->first]); int old_charge = atom->GetFormalCharge(); atom->SetFormalCharge(j->second); int new_hcount = atom->GetImplicitHCount() + (j->second - old_charge); if (new_hcount < 0) new_hcount = 0; atom->SetImplicitHCount(new_hcount); } } if (!_vbond.empty()) //modify bond orders { OBBond *bond; vector<vector<int> >::iterator i; vector<pair<pair<int,int>,int> >::iterator j; for (i = mlist.begin();i != mlist.end();++i) for (j = _vbond.begin();j != _vbond.end();++j) { bond = mol.GetBond((*i)[j->first.first],(*i)[j->first.second]); if (!bond) { obErrorLog.ThrowError(__FUNCTION__, "unable to find bond", obDebug); continue; } unsigned int old_bond_order = bond->GetBondOrder(); bond->SetBondOrder(j->second); for (int k = 0; k < 2; ++k) { OBAtom* atom = k == 0 ? bond->GetBeginAtom() : bond->GetEndAtom(); int new_hcount = atom->GetImplicitHCount() - (j->second - old_bond_order); if (new_hcount < 0) new_hcount = 0; atom->SetImplicitHCount(new_hcount); } } } if (!_vadel.empty() || !_vele.empty()) //delete atoms and change elements { vector<int>::iterator j; vector<vector<int> >::iterator i; if (!_vele.empty()) { vector<pair<int,int> >::iterator k; for (i = mlist.begin();i != mlist.end();++i) for (k = _vele.begin();k != _vele.end();++k) mol.GetAtom((*i)[k->first])->SetAtomicNum(k->second); } //make sure same atom isn't deleted twice vector<bool> vda; vector<OBAtom*> vdel; vda.resize(mol.NumAtoms()+1,false); for (i = mlist.begin();i != mlist.end();++i) for (j = _vadel.begin();j != _vadel.end();++j) if (!vda[(*i)[*j]]) { vda[(*i)[*j]] = true; vdel.push_back(mol.GetAtom((*i)[*j])); } vector<OBAtom*>::iterator k; for (k = vdel.begin();k != vdel.end();++k) mol.DeleteAtom((OBAtom*)*k); } mol.EndModify(); return(true); }
bool ChemDrawXMLFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) { static const xmlChar C_MOLECULE[] = "fragment"; static const xmlChar C_CDXML[] = "CDXML"; static const xmlChar C_BONDLENGTH[] = "BondLength"; static const xmlChar C_PAGE[] = "page"; static const xmlChar C_ATOM[] = "n"; static const xmlChar C_BOND[] = "b"; static const xmlChar C_ID[] = "id"; static const xmlChar C_CHARGE[] = "Charge"; static const xmlChar C_COORDS[] = "p"; static const xmlChar C_ELEMENT[] = "Element"; static const xmlChar C_ORDER[] = "Order"; static const xmlChar C_BEGIN[] = "B"; static const xmlChar C_END[] = "E"; static const xmlChar C_DISPLAY[] = "Display"; _pxmlConv = XMLConversion::GetDerived(pConv,false); if(!_pxmlConv) return false; OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(pmol==NULL) return false; OBMol &mol = *pmol; OBBond *pbond; vector<OBBond*>::iterator j; if(_pxmlConv->GetOutputIndex() == 1) { xmlTextWriterStartDocument(writer(), NULL, NULL, NULL); xmlTextWriterWriteDTD(writer(), BAD_CAST "CDXML", NULL, BAD_CAST "http://www.camsoft.com/xml/cdxml.dtd", NULL); xmlTextWriterStartElement(writer(), C_CDXML); xmlTextWriterWriteFormatAttribute(writer(), C_BONDLENGTH , "30"); xmlTextWriterStartElement(writer(), C_PAGE); // put everything on one page // now guess the average bond size for the first molecule and scale to 30. _scale = 0.; if (mol.NumBonds()) { for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j)) _scale += pbond->GetLength(); _scale /= mol.NumBonds(); } else _scale = 1.; // FIXME: what happens if the molecule has no bond? _scale = 30. / _scale; _offset = 0; } xmlTextWriterStartElement(writer(), C_MOLECULE); OBAtom *patom; vector<OBAtom*>::iterator i; int n; for (patom = mol.BeginAtom(i); patom; patom = mol.NextAtom(i)) { xmlTextWriterStartElement(writer(), C_ATOM); xmlTextWriterWriteFormatAttribute(writer(), C_ID , "%d", patom->GetIdx() + _offset); xmlTextWriterWriteFormatAttribute(writer(), C_COORDS , "%f %f", patom->GetX() * _scale, patom->GetY() * _scale); n = patom->GetAtomicNum(); if (n != 6) { xmlTextWriterWriteFormatAttribute(writer(), C_ELEMENT , "%d", n); } n = patom->GetFormalCharge(); if (n != 0) { xmlTextWriterWriteFormatAttribute(writer(), C_CHARGE , "%d", n); } xmlTextWriterEndElement(writer()); } for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j)) { xmlTextWriterStartElement(writer(), C_BOND); patom = pbond->GetBeginAtom(); xmlTextWriterWriteFormatAttribute(writer(), C_BEGIN , "%d", patom->GetIdx() + _offset); patom = pbond->GetEndAtom(); xmlTextWriterWriteFormatAttribute(writer(), C_END , "%d", patom->GetIdx() + _offset); n = pbond->GetBO(); if (n != 1) { xmlTextWriterWriteFormatAttribute(writer(), C_ORDER , "%d", n); } if (pbond->IsHash()) xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgeBegin"); else if (pbond->IsWedge()) xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgedHashEnd"); xmlTextWriterEndElement(writer()); } _offset += mol.NumAtoms (); xmlTextWriterEndElement(writer());//molecule //TODO: Writing property block if(_pxmlConv->IsLast()) { xmlTextWriterEndDocument(writer()); // page xmlTextWriterEndDocument(writer()); //document OutputToStream(); } return true; }
bool OBDepict::DrawMolecule(OBMol *mol) { if (!d->painter) return false; d->mol = mol; double width=0.0, height=0.0; OBAtom *atom; OBBondIterator j; OBAtomIterator i; if(mol->NumAtoms()>0) { // scale bond lengths double bondLengthSum = 0.0; for (OBBond *bond = mol->BeginBond(j); bond; bond = mol->NextBond(j)) bondLengthSum += bond->GetLength(); const double averageBondLength = bondLengthSum / mol->NumBonds(); const double f = mol->NumBonds() ? d->bondLength / averageBondLength : 1.0; for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) atom->SetVector(atom->GetX() * f, atom->GetY() * f, 0.0); // find min/max values double min_x, max_x; double min_y, max_y; atom = mol->BeginAtom(i); min_x = max_x = atom->GetX(); min_y = max_y = atom->GetY(); for (atom = mol->NextAtom(i); atom; atom = mol->NextAtom(i)) { min_x = std::min(min_x, atom->GetX()); max_x = std::max(max_x, atom->GetX()); min_y = std::min(min_y, atom->GetY()); max_y = std::max(max_y, atom->GetY()); } const double margin = 40.0; // translate all atoms so the bottom-left atom is at margin,margin for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) atom->SetVector(atom->GetX() - min_x + margin, atom->GetY() - min_y + margin, 0.0); width = max_x - min_x + 2*margin; height = max_y - min_y + 2*margin; //d->painter->SetPenWidth(d->penWidth); //d->painter->SetPenColor(d->pen)); //d->painter->SetFillColor(OBColor("black")); } d->painter->NewCanvas(width, height); // draw bonds if(d->options & genWedgeHash) d->SetWedgeAndHash(mol); for (OBBond *bond = mol->BeginBond(j); bond; bond = mol->NextBond(j)) { OBAtom *begin = bond->GetBeginAtom(); OBAtom *end = bond->GetEndAtom(); if((d->options & internalColor) && bond->HasData("color")) d->painter->SetPenColor(OBColor(bond->GetData("color")->GetValue())); else d->painter->SetPenColor(d->bondColor); if (bond->IsWedge()) { d->DrawWedge(begin, end); } else if (bond->IsHash()) { d->DrawHash(begin, end); } else if (!bond->IsInRing()) { d->DrawSimpleBond(begin, end, bond->GetBO()); } } // draw ring bonds std::vector<OBRing*> rings(mol->GetSSSR()); OBBitVec drawnBonds; for (std::vector<OBRing*>::iterator k = rings.begin(); k != rings.end(); ++k) { OBRing *ring = *k; std::vector<int> indexes = ring->_path; vector3 center(VZero); for (std::vector<int>::iterator l = indexes.begin(); l != indexes.end(); ++l) { center += mol->GetAtom(*l)->GetVector(); } center /= indexes.size(); for (unsigned int l = 0; l < indexes.size(); ++l) { OBAtom *begin = mol->GetAtom(indexes[l]); OBAtom *end; if (l+1 < indexes.size()) end = mol->GetAtom(indexes[l+1]); else end = mol->GetAtom(indexes[0]); OBBond *ringBond = mol->GetBond(begin, end); if (drawnBonds.BitIsSet(ringBond->GetId())) continue; if((d->options & internalColor) && ringBond->HasData("color")) d->painter->SetPenColor(OBColor(ringBond->GetData("color")->GetValue())); else d->painter->SetPenColor(d->bondColor); d->DrawRingBond(begin, end, center, ringBond->GetBO()); drawnBonds.SetBitOn(ringBond->GetId()); } } // draw atom labels for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) { double x = atom->GetX(); double y = atom->GetY(); int alignment = GetLabelAlignment(atom); bool rightAligned = false; switch (alignment) { case TopRight: case CenterRight: case BottomRight: rightAligned = true; default: break; } if((d->options & internalColor) && atom->HasData("color")) d->painter->SetPenColor(OBColor(atom->GetData("color")->GetValue())); else if(d->options & bwAtoms) d->painter->SetPenColor(d->bondColor); else d->painter->SetPenColor(OBColor(etab.GetRGB(atom->GetAtomicNum()))); //charge and radical int charge = atom->GetFormalCharge(); int spin = atom->GetSpinMultiplicity(); if(charge || spin) { OBFontMetrics metrics = d->painter->GetFontMetrics("N"); double yoffset = d->HasLabel(atom) ? 0.4 * metrics.height : 0.0; switch (GetLabelAlignment(atom)) { case TopCenter: case TopRight: case TopLeft: case CenterLeft: case CenterRight: yoffset = - 1.2 * metrics.height; } stringstream ss; if(charge) { if(abs(charge)!=1) ss << abs(charge); ss << (charge>0 ? "+" : "-") ; } if(spin) { ss << (spin==2 ? "." : ".."); yoffset += 0.5 * metrics.height; } if(spin || charge<0) d->painter->SetFontSize(2 * metrics.fontSize); d->painter->DrawText(x-0.4*metrics.width, y-yoffset, ss.str()); d->painter->SetFontSize(metrics.fontSize);//restore } if (atom->IsCarbon()) { if(!(d->options & drawAllC)) { if (atom->GetValence() > 1) continue; if ((atom->GetValence() == 1) && !(d->options & drawTermC))//!d->drawTerminalC) continue; } } stringstream ss; AliasData* ad = NULL; if(d->aliasMode && atom->HasData(AliasDataType)) ad = static_cast<AliasData*>(atom->GetData(AliasDataType)); //For unexpanded aliases use appropriate form of alias instead of element symbol, Hs, etc if(ad && !ad->IsExpanded()) { ss <<ad->GetAlias(rightAligned); OBColor aliasColor = !ad->GetColor().empty() ? ad->GetColor() : d->bondColor; d->painter->SetPenColor(aliasColor); } else { const char* atomSymbol; if(atom->IsHydrogen() && atom->GetIsotope()>1) atomSymbol = atom->GetIsotope()==2 ? "D" : "T"; else atomSymbol = etab.GetSymbol(atom->GetAtomicNum()); unsigned int hCount = atom->ImplicitHydrogenCount(); // rightAligned: // false CH3 // true H3C if (hCount && rightAligned) ss << "H"; if ((hCount > 1) && rightAligned) ss << hCount; ss << atomSymbol; if (hCount && !rightAligned) ss << "H"; if ((hCount > 1) && !rightAligned) ss << hCount; } d->DrawAtomLabel(ss.str(), alignment, vector3(x, y, 0.0)); } return true; }
void OutputCSTBonds(ostream &ofs, OBMol &mol, string prefix) { string bond_type; /* ---- Write povray-description of all bonds---- */ for(unsigned int i = 0; i < mol.NumBonds(); ++i) { double x1,y1,z1,x2,y2,z2; /* Start and stop coordinates of a bond */ double dist; /* Distance between (x1|y1|z1) and (x2|y2|z2) */ double phi,theta; /* Angles between (x1|y1|z1) and (x2|y2|z2) */ double dy; /* Distance between (x1|0|z1) and (x2|0|z2) */ /* ---- Get a pointer to ith atom ---- */ OBBond *bond = mol.GetBond(i); /* ---- Assign start of bond i ---- */ x1 = (bond -> GetBeginAtom()) -> GetX(); y1 = (bond -> GetBeginAtom()) -> GetY(); z1 = (bond -> GetBeginAtom()) -> GetZ(); /* ---- Assign end of bond i ---- */ x2 = (bond -> GetEndAtom()) -> GetX(); y2 = (bond -> GetEndAtom()) -> GetY(); z2 = (bond -> GetEndAtom()) -> GetZ(); /* ---- Calculate length of bond and (x1|0|z1) - (x2|0|z2) ---- */ dist = sqrt(SQUARE(x2-x1) + SQUARE(y2-y1) + SQUARE(z2-z1)); dy = sqrt(SQUARE(x2-x1) + SQUARE(z2-z1)); /* ---- Calculate Phi and Theta ---- */ phi = (double) 0.0; theta = (double) 0.0; if (fabs(dist) >= EPSILON) phi = acos((y2-y1)/dist); if (fabs(dy) >= EPSILON) theta = acos((x2-x1)/dy); /* ---- Begin of description of bond i (for a capped sticks model) ---- */ ofs << "#declare " << prefix << "_bond" << i << " = object {" << endl; ofs << "\t union {" << endl; /* ---- Begin of Start-Half of Bond (i) ---- */ ofs << "\t object {" << endl << "\t bond_" << bond -> GetBondOrder() << "\n"; /* ---- Add a pigment - statement for start-atom of bond ---- */ bond_type = bond->GetBeginAtom() -> GetType(); bond_type.erase(remove_if(bond_type.begin(), bond_type.end(), bind1st(equal_to<char>(), '.')), bond_type.end()); ofs << "\t pigment{color Color_" << bond_type << "}" << endl; /* ---- Scale bond if needed ---- */ if (fabs((double) 2.0 * dist) >= EPSILON) { /* ---- Print povray scale-statement (x-Axis) ---- */ ofs << "\t scale <" << (double) 0.5 * dist << ",1.0000,1.0000>" << endl; } /* ---- Rotate (Phi) bond if needed ---- */ if (fabs(RAD2DEG(-phi) + (double) 90.0) >= EPSILON) { /* ---- Rotate along z-axis ---- */ ofs << "\t rotate <0.0000,0.0000," << RAD2DEG(-phi) + (double) 90.0 << ">" << endl; } /* ---- Check angle between (x1|0|z1) and (x2|0|z2) ---- */ if (theta >= EPSILON) { /* ---- Check direction ---- */ if ((z2 - z1) >= (double) 0.0) { /* ---- Rotate along y-Axis (negative) ---- */ ofs << "\t rotate <0.0000," << RAD2DEG((double) -1.0 *theta) << ",0.0000>" << endl; } else { /* ---- Rotate along y-Axis (positive) ---- */ ofs << "\t rotate <0.0000," << RAD2DEG(theta) << ",0.0000>" << endl; } } /* ---- Translate bond to start ---- */ ofs << "\t translate " << prefix << "_pos_" << bond -> GetBeginAtomIdx() << endl; /* ---- End of description of Start-Bond ---- */ ofs << "\t }" << endl; /* ---- Begin of End-Half of Bond i ---- */ ofs << "\t object {" << endl << "\t bond_" << bond -> GetBondOrder() << endl; /* ---- Add a pigment - statement for end-atom of bond i ---- */ bond_type = bond->GetEndAtom() -> GetType(); bond_type.erase(remove_if(bond_type.begin(), bond_type.end(), bind1st(equal_to<char>(), '.')), bond_type.end()); ofs << "\t pigment{color Color_" << bond_type << "}" << endl; /* ---- Scale bond if needed ---- */ if (fabs((double) 2.0 * dist) >= EPSILON) { /* ---- Print povray scale-statement (x-Axis) ---- */ ofs << "\t scale <" << (double) 0.5 * dist << ",1.0000,1.0000>" << endl; } /* ---- Rotate (Phi) bond if needed ---- */ if (fabs(RAD2DEG(-phi) + (double) 270.0) >= EPSILON) { /* ---- Rotate along z-axis (oposite to start half) ---- */ ofs << "\t rotate <0.0000,0.0000," << (RAD2DEG(-phi) + (double) 90.0) + (double) 180.0 << ">" << endl; } /* ---- Check angle between (x1|0|z1) and (x2|0|z2) ---- */ if (fabs(theta) >= EPSILON) { /* ---- Check direction ---- */ if ((z2 - z1) >= (double) 0.0) { /* ---- Rotate along y-Axis (negative) (oposite orientation) ---- */ ofs << "\t rotate <0.0000," << RAD2DEG((double) -1.0 * theta) << ",0.0000>" << endl; } else { /* ---- Rotate along y-Axis (positive) (oposite orientation) ---- */ ofs << "\t rotate <0.0000," << RAD2DEG(theta) << ",0.0000>" << endl; } } /* ---- Translate bond to end ---- */ ofs << "\t translate " << prefix << "_pos_" << bond -> GetEndAtomIdx() << endl; /* ---- End of description of End-Bond ---- */ ofs << "\t }" << endl; /* ---- End of description of bond i ---- */ ofs << "\t }" << endl << "\t }" << endl << endl; } }
//! Calculate the signed volume for an atom. If the atom has a valence of 3 //! the coordinates of an attached hydrogen are calculated //! Puts attached Hydrogen last at the moment, like mol V3000 format. //! If ReZero=false (the default is true) always make pseudo z coords and leave them in mol double CalcSignedVolume(OBMol &mol,OBAtom *atm, bool ReZeroZ) { vector3 tmp_crd; vector<unsigned int> nbr_atms; vector<vector3> nbr_crds; bool use_central_atom = false,is2D=false; // double hbrad = etab.CorrectedBondRad(1,0); if (!ReZeroZ || !mol.Has3D()) //give pseudo Z coords if mol is 2D { vector3 v,vz(0.0,0.0,1.0); is2D = true; OBAtom *nbr; OBBond *bond; vector<OBBond*>::iterator i; for (bond = atm->BeginBond(i);bond;bond = atm->NextBond(i)) { nbr = bond->GetEndAtom(); if (nbr != atm) { v = nbr->GetVector(); if (bond->IsWedge()) v += vz; else if (bond->IsHash()) v -= vz; nbr->SetVector(v); } else { nbr = bond->GetBeginAtom(); v = nbr->GetVector(); if (bond->IsWedge()) v -= vz; else if (bond->IsHash()) v += vz; nbr->SetVector(v); } } } if (atm->GetHvyValence() < 3) { stringstream errorMsg; errorMsg << "Cannot calculate a signed volume for an atom with a heavy atom valence of " << atm->GetHvyValence() << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obInfo); return(0.0); } // Create a vector with the coordinates of the neighbor atoms // Also make a vector with Atom IDs OBAtom *nbr; vector<OBBond*>::iterator bint; for (nbr = atm->BeginNbrAtom(bint);nbr;nbr = atm->NextNbrAtom(bint)) { nbr_atms.push_back(nbr->GetIdx()); } // sort the neighbor atoms to insure a consistent ordering sort(nbr_atms.begin(),nbr_atms.end()); for (unsigned int i = 0; i < nbr_atms.size(); ++i) { OBAtom *tmp_atm = mol.GetAtom(nbr_atms[i]); nbr_crds.push_back(tmp_atm->GetVector()); } /* // If we have three heavy atoms we need to calculate the position of the fourth if (atm->GetHvyValence() == 3) { double bondlen = hbrad+etab.CorrectedBondRad(atm->GetAtomicNum(),atm->GetHyb()); atm->GetNewBondVector(tmp_crd,bondlen); nbr_crds.push_back(tmp_crd); } */ for(unsigned int j=0;j < nbr_crds.size();++j) // Checks for a neighbour having 0 co-ords (added hydrogen etc) { // are the coordinates zero to 6 or more significant figures if (nbr_crds[j].IsApprox(VZero, 1.0e-6) && use_central_atom==false) use_central_atom=true; else if (nbr_crds[j].IsApprox(VZero, 1.0e-6)) { obErrorLog.ThrowError(__FUNCTION__, "More than 2 neighbours have 0 co-ords when attempting 3D chiral calculation", obInfo); } } // If we have three heavy atoms we can use the chiral center atom itself for the fourth // will always give same sign (for tetrahedron), magnitude will be smaller. if(nbr_atms.size()==3 || use_central_atom==true) { nbr_crds.push_back(atm->GetVector()); nbr_atms.push_back(mol.NumAtoms()+1); // meed to add largest number on end to work } OBChiralData* cd=(OBChiralData*)atm->GetData(OBGenericDataType::ChiralData); //Set the output atom4refs to the ones used if(cd==NULL) { cd = new OBChiralData; cd->SetOrigin(perceived); atm->SetData(cd); } cd->SetAtom4Refs(nbr_atms,calcvolume); //re-zero psuedo-coords if (is2D && ReZeroZ) { vector3 v; OBAtom *atom; vector<OBAtom*>::iterator k; for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k)) { v = atom->GetVector(); v.SetZ(0.0); atom->SetVector(v); } } return(signed_volume(nbr_crds[0],nbr_crds[1],nbr_crds[2],nbr_crds[3])); }