void MoleculeInChI::_normalizeMolecule(Molecule &mol) { QS_DEF(Array<int>, ignored); ignored.clear_resize(mol.vertexEnd()); ignored.zerofill(); for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) if (mol.convertableToImplicitHydrogen(i)) ignored[i] = 1; for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) if (mol.getBondTopology(i) == TOPOLOGY_RING) mol.cis_trans.setParity(i, 0); MoleculeAutomorphismSearch of; of.detect_invalid_cistrans_bonds = true; of.detect_invalid_stereocenters = true; of.find_canonical_ordering = false; of.ignored_vertices = ignored.ptr(); of.process(mol); for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) if (mol.cis_trans.getParity(i) != 0 && of.invalidCisTransBond(i)) mol.cis_trans.setParity(i, 0); for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) if (mol.stereocenters.getType(i) > MoleculeStereocenters::ATOM_ANY && of.invalidStereocenter(i)) mol.stereocenters.remove(i); }
bool MoleculeAromatizer::aromatizeBonds (Molecule &mol, const AromaticityOptions &options) { MoleculeAromatizer aromatizer(mol, options); aromatizer.precalculatePiLabels(); aromatizer.aromatize(); bool aromatic_bond_found = false; for (int e_idx = mol.edgeBegin(); e_idx < mol.edgeEnd(); e_idx = mol.edgeNext(e_idx)) if (aromatizer.isBondAromatic(e_idx)) { mol.setBondOrder(e_idx, BOND_AROMATIC, true); aromatic_bond_found = true; } // Aromatize RGroups int n_rgroups = mol.rgroups.getRGroupCount(); for (int i = 1; i <= n_rgroups; i++) { PtrPool<BaseMolecule> &frags = mol.rgroups.getRGroup(i).fragments; for (int j = frags.begin(); j != frags.end(); j = frags.next(j)) { Molecule &fragment = frags[j]->asMolecule(); aromatic_bond_found |= MoleculeAromatizer::aromatizeBonds(fragment, options); } } return aromatic_bond_found; }
bool MoleculeAutomorphismSearch::_hasStereo (Molecule &mol) { for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) if (mol.cis_trans.getParity(i) != 0) return true; if (mol.stereocenters.size() != 0) return true; return false; }
void IndigoInchi::saveMoleculeIntoInchi (Molecule &mol, Array<char> &inchi) { inchi_Input input; QS_DEF(Array<inchi_Atom>, atoms); QS_DEF(Array<inchi_Stereo0D>, stereo); // Check if structure has aromatic bonds bool has_aromatic = false; for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e)) if (mol.getBondOrder(e) == BOND_AROMATIC) { has_aromatic = true; break; } Molecule *target = &mol; Obj<Molecule> dearom; if (has_aromatic) { dearom.create(); dearom->clone(mol, 0, 0); try { dearom->dearomatize(); } catch (DearomatizationsGroups::Error &) { } target = dearom.get(); } generateInchiInput(*target, input, atoms, stereo); inchi_Output output; int ret = GetINCHI(&input, &output); if (output.szMessage) warning.readString(output.szMessage, true); if (output.szLog) log.readString(output.szLog, true); if (output.szAuxInfo) auxInfo.readString(output.szAuxInfo, true); if (ret != inchi_Ret_OKAY && ret != inchi_Ret_WARNING) { // Construct error before dispoing inchi output to preserve error message IndigoError error("Indigo-InChI: InChI generation failed: %s. Code: %d.", output.szMessage, ret); FreeINCHI(&output); throw error; } inchi.readString(output.szInChI, true); FreeINCHI(&output); }
void MangoExact::_initQuery (Molecule &query) { int i; MoleculeAromatizer::aromatizeBonds(query, AromaticityOptions::BASIC); if (_flags & MoleculeExactMatcher::CONDITION_STEREO) { for (i = query.edgeBegin(); i != query.edgeEnd(); i = query.edgeNext(i)) if (query.getEdgeTopology(i) == TOPOLOGY_RING) query.cis_trans.setParity(i, 0); } }
void MoleculeAutomorphismSearch::_markComplicatedStereocentersAsValid (Molecule &mol) { // If there is more then 1 unknown stereocenter in the biconnected // component then validity of such stereocenters cannot be found // with current methods. For example C[C@H]1C[C@@H](C)C[C@H](C)C1 // can lead to CC1C[C@H](C)C[C@@H](C)C1 or CC1C[C@@H](C)C[C@H](C)C1, // but canonical codes are different for such molecules. QS_DEF(Array<int>, single_bond_bridge_mark); single_bond_bridge_mark.resize(mol.edgeEnd()); single_bond_bridge_mark.fill(1); SpanningTree sp_tree(mol, 0); sp_tree.markAllEdgesInCycles(single_bond_bridge_mark.ptr(), 0); for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i++) if (mol.getBondOrder(i) != BOND_SINGLE) single_bond_bridge_mark[i] = 0; Filter edge_filter(single_bond_bridge_mark.ptr(), Filter::NEQ, 1); GraphDecomposer decomposer(mol); decomposer.decompose(0, &edge_filter); const Array<int> &decomposition = decomposer.getDecomposition(); QS_DEF(Array<int>, undef_stereo_in_component); undef_stereo_in_component.clear(); for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) { int comp = decomposition[v]; if (comp < 0) continue; while (undef_stereo_in_component.size() <= comp) undef_stereo_in_component.push(0); if (_stereocenter_state[v] == _UNDEF) undef_stereo_in_component[comp]++; } // Mark stereocenters as valid if there are more then 1 // undefined stereocenter in the component for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) { int comp = decomposition[v]; if (comp < 0) continue; if (_stereocenter_state[v] == _UNDEF && undef_stereo_in_component[comp] > 1) _stereocenter_state[v] = _VALID; } }
void MoleculePiSystemsMatcher::_calcConnectivity (Molecule &mol, Array<int> &conn) { conn.clear_resize(mol.vertexEnd()); conn.zerofill(); for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e)) { int bond_order = mol.getBondOrder(e); const Edge &edge = mol.getEdge(e); conn[edge.beg] += bond_order; conn[edge.end] += bond_order; } for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) if (!mol.isPseudoAtom(v) && !mol.isRSite(v)) conn[v] += mol.getImplicitH(v); }
void MoleculeAutomorphismSearch::_getFirstApproximation (Molecule &mol) { _stereocenter_state.clear_resize(mol.vertexEnd()); _cistrans_bond_state.clear_resize(mol.edgeEnd()); const MoleculeStereocenters &stereocenters = mol.stereocenters; for (int i = 0; i < _stereocenter_state.size(); i++) _stereocenter_state[i] = _NO_STEREO; for (int i = stereocenters.begin(); i != stereocenters.end(); i = stereocenters.next(i)) { int atom_index = stereocenters.getAtomIndex(i); _stereocenter_state[atom_index] = _UNDEF; } for (int i = 0; i < _cistrans_bond_state.size(); i++) _cistrans_bond_state[i] = _NO_STEREO; for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) if (mol.cis_trans.getParity(i)) _cistrans_bond_state[i] = _UNDEF; _cistrans_stereo_bond_parity.clear_resize(mol.edgeEnd()); _cistrans_stereo_bond_parity.zerofill(); _treat_undef_as = _INVALID; _target_stereocenter = -1; _target_bond = -1; // Approximation orbits cannot be used on this step because // of existance of check_automorphism method. But order from // first refinment can be used here. _approximation_orbits.fffill(); profTimerStart(t0, "mol_auto.first_search"); AutomorphismSearch::process(mol); profTimerStop(t0); getCanonicallyOrderedOrbits(_approximation_orbits); _findCisTransStereoBondParirties(mol); }
bool MoleculeAutomorphismSearch::_findInvalidStereoCisTrans (Molecule &mol) { _treat_undef_as = _VALID; QS_DEF(Array<int>, invalid_stereo); invalid_stereo.clear(); bool invalid_found = false; for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) { if (_cistrans_bond_state[i] != _UNDEF || mol.cis_trans.getParity(i) == 0) continue; if (ignored_vertices != 0) { const Edge &edge = mol.getEdge(i); if (ignored_vertices[edge.beg] || ignored_vertices[edge.end]) continue; } _cistrans_bond_state[i] = _INVALID; if (_checkCisTransInvalid(mol, i)) // Stereobond is invalid invalid_stereo.push(i); _cistrans_bond_state[i] = _UNDEF; } // Mark invalid stereocenters for (int i = 0; i < invalid_stereo.size(); i++) { int bond_index = invalid_stereo[i]; _cistrans_bond_state[bond_index] = _INVALID; invalid_found = true; } return invalid_found; }
void MoleculeAutomorphismSearch::_findCisTransStereoBondParirties (Molecule &mol) { const MoleculeStereocenters &stereocenters = mol.stereocenters; // Mark edges that connects two stereocenters and that common parity can be detected for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge &edge = mol.getEdge(i); if (!stereocenters.exists(edge.beg) || !stereocenters.exists(edge.end)) continue; if (stereocenters.getGroup(edge.beg) != stereocenters.getGroup(edge.end)) continue; if (stereocenters.getType(edge.beg) != stereocenters.getType(edge.end)) continue; // Both stereocenters exists and groups are the same int orb_beg = _approximation_orbits[edge.beg]; int orb_end = _approximation_orbits[edge.end]; _approximation_orbits[edge.beg] = -2; // Some value different from -1 and other orbits _approximation_orbits[edge.end] = -2; int parity_beg, parity_end; if (_validStereocenterByAtom(edge.beg, _approximation_orbits, &parity_beg) == _VALID && _validStereocenterByAtom(edge.end, _approximation_orbits, &parity_end) == _VALID) { // 1 - means that both stereocenters have the same parity _cistrans_stereo_bond_parity[i] = -parity_beg * parity_end; } // Restore orbits _approximation_orbits[edge.beg] = orb_beg; _approximation_orbits[edge.end] = orb_end; } }
void IndigoInchi::generateInchiInput (Molecule &mol, inchi_Input &input, Array<inchi_Atom> &atoms, Array<inchi_Stereo0D> &stereo) { QS_DEF(Array<int>, mapping); mapping.clear_resize(mol.vertexEnd()); mapping.fffill(); int index = 0; for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) mapping[v] = index++; atoms.clear_resize(index); atoms.zerofill(); stereo.clear(); for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) { inchi_Atom &atom = atoms[mapping[v]]; int atom_number = mol.getAtomNumber(v); if (atom_number == ELEM_PSEUDO) throw IndigoError("Molecule with pseudoatom (%s) cannot be converted into InChI", mol.getPseudoAtom(v)); if (atom_number == ELEM_RSITE) throw IndigoError("Molecule with RGroups cannot be converted into InChI"); strncpy(atom.elname, Element::toString(atom_number), ATOM_EL_LEN); Vec3f &c = mol.getAtomXyz(v); atom.x = c.x; atom.y = c.y; atom.z = c.z; // connectivity const Vertex &vtx = mol.getVertex(v); int nei_idx = 0; for (int nei = vtx.neiBegin(); nei != vtx.neiEnd(); nei = vtx.neiNext(nei)) { int v_nei = vtx.neiVertex(nei); atom.neighbor[nei_idx] = mapping[v_nei]; int edge_idx = vtx.neiEdge(nei); atom.bond_type[nei_idx] = getInchiBondType(mol.getBondOrder(edge_idx)); int bond_stereo = INCHI_BOND_STEREO_NONE; if (mol.cis_trans.isIgnored(edge_idx)) bond_stereo = INCHI_BOND_STEREO_DOUBLE_EITHER; else { int dir = mol.getBondDirection2(v, v_nei); if (mol.getBondDirection2(v, v_nei) == BOND_EITHER) bond_stereo = INCHI_BOND_STEREO_SINGLE_1EITHER; else if (mol.getBondDirection2(v_nei, v) == BOND_EITHER) bond_stereo = INCHI_BOND_STEREO_SINGLE_2EITHER; } atom.bond_stereo[nei_idx] = bond_stereo; nei_idx++; } atom.num_bonds = vtx.degree(); // Other properties atom.isotopic_mass = mol.getAtomIsotope(v); atom.radical = mol.getAtomRadical(v); atom.charge = mol.getAtomCharge(v); // Hydrogens int hcount = -1; if (Molecule::shouldWriteHCount(mol, v) || mol.isExplicitValenceSet(v) || mol.isImplicitHSet(v)) { if (mol.getAtomAromaticity(v) == ATOM_AROMATIC && atom_number == ELEM_C && atom.charge == 0 && atom.radical == 0) { // Do not set number of implicit hydrogens here as InChI throws an exception on // the molecule B1=CB=c2cc3B=CC=c3cc12 ; } else // set -1 to tell InChI add implicit hydrogens automatically hcount = mol.getImplicitH_NoThrow(v, -1); } atom.num_iso_H[0] = hcount; } // Process cis-trans bonds for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e)) { if (mol.cis_trans.getParity(e) == 0) continue; int subst[4]; mol.cis_trans.getSubstituents_All(e, subst); const Edge &edge = mol.getEdge(e); inchi_Stereo0D &st = stereo.push(); // Write it as // #0 - #1 = #2 - #3 st.neighbor[0] = mapping[subst[0]]; st.neighbor[1] = mapping[edge.beg]; st.neighbor[2] = mapping[edge.end]; st.neighbor[3] = mapping[subst[2]]; if (mol.cis_trans.getParity(e) == MoleculeCisTrans::CIS) st.parity = INCHI_PARITY_ODD; else st.parity = INCHI_PARITY_EVEN; st.central_atom = NO_ATOM; st.type = INCHI_StereoType_DoubleBond; } // Process tetrahedral stereocenters for (int i = mol.stereocenters.begin(); i != mol.stereocenters.end(); i = mol.stereocenters.next(i)) { int v = mol.stereocenters.getAtomIndex(i); int type, group, pyramid[4]; mol.stereocenters.get(v, type, group, pyramid); if (type == MoleculeStereocenters::ATOM_ANY) continue; for (int i = 0; i < 4; i++) if (pyramid[i] != -1) pyramid[i] = mapping[pyramid[i]]; inchi_Stereo0D &st = stereo.push(); /* 4 neighbors X neighbor[4] : {#W, #X, #Y, #Z} | central_atom: #A W--A--Y type : INCHI_StereoType_Tetrahedral | Z parity: if (X,Y,Z) are clockwize when seen from W then parity is 'e' otherwise 'o' Example (see AXYZW above): if W is above the plane XYZ then parity = 'e' 3 neighbors Y Y neighbor[4] : {#A, #X, #Y, #Z} / / central_atom: #A X--A (e.g. O=S ) type : INCHI_StereoType_Tetrahedral \ \ Z Z */ int offset = 0; if (pyramid[3] == -1) offset = 1; st.neighbor[offset] = mapping[pyramid[0]]; st.neighbor[offset + 1] = mapping[pyramid[1]]; st.neighbor[offset + 2] = mapping[pyramid[2]]; if (offset == 0) st.neighbor[3] = mapping[pyramid[3]]; else st.neighbor[0] = mapping[v]; st.parity = INCHI_PARITY_ODD; if (offset != 0) st.parity = INCHI_PARITY_ODD; else st.parity = INCHI_PARITY_EVEN; st.central_atom = mapping[v]; st.type = INCHI_StereoType_Tetrahedral; } input.atom = atoms.ptr(); input.num_atoms = atoms.size(); input.stereo0D = stereo.ptr(); input.num_stereo0D = stereo.size(); input.szOptions = options.ptr(); }
void MoleculeAutomorphismSearch::process (Molecule &mol) { _initialize(mol); if (detect_invalid_stereocenters || detect_invalid_cistrans_bonds) { // Mark stereocenters that are valid _markValidOrInvalidStereo(true, _approximation_orbits, NULL); _markValidOrInvalidStereo(false, _approximation_orbits, NULL); // Temposrary solution: mark unknown stereocenters as valid if // number of them is more then 1 in each component _markComplicatedStereocentersAsValid(mol); // Find invalid stereocenters and bonds iteratively // For each component const int *ignored_vertices_saved = ignored_vertices; GraphDecomposer decomposer(mol); int ncomp = decomposer.decompose(); QS_DEF(Array<int>, ignored_vertices_arr); ignored_vertices_arr.resize(mol.vertexEnd()); ignored_vertices = ignored_vertices_arr.ptr(); for (int comp = 0; comp < ncomp; comp++) { // Copy existing ignores vertices if (ignored_vertices_saved != 0) ignored_vertices_arr.copy(ignored_vertices_saved, mol.vertexEnd()); else ignored_vertices_arr.zerofill(); for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { if (decomposer.getComponent(i) != comp) ignored_vertices_arr[i] = 1; } while (_findInvalidStereo(mol)) ; } ignored_vertices = ignored_vertices_saved; } // Mark all other stereocenters and stereobonds as valid const MoleculeStereocenters &stereocenters = mol.stereocenters; for (int i = stereocenters.begin(); i != stereocenters.end(); i = stereocenters.next(i)) { int atom_index = stereocenters.getAtomIndex(i); if (_stereocenter_state[atom_index] == _UNDEF) _stereocenter_state[atom_index] = _VALID; } for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) if (_cistrans_bond_state[i] == _UNDEF && mol.cis_trans.getParity(i) != 0) _cistrans_bond_state[i] = _VALID; // Find final orbits and canonical ordering with found // valid and invalid stereocenters and bonds _target_stereocenter = -1; _target_bond = -1; _fixed_atom = -1; // Find possible cis-trans bonds _findAllPossibleCisTrans(mol); if (find_canonical_ordering) { profTimerStart(t0, "mol_auto.final_search"); AutomorphismSearch::process(mol); profTimerStop(t0); } }
TautomerSuperStructure::TautomerSuperStructure (Molecule &mol) : CP_INIT, TL_CP_GET(_atomsEmitBond), TL_CP_GET(_atomsAcceptBond), TL_CP_GET(_isBondAttachedArray), TL_CP_GET(_mapping), TL_CP_GET(_inv_mapping), TL_CP_GET(_edge_mapping), TL_CP_GET(_total_h) { int i; _inside_ctor = true; clone(mol, &_inv_mapping, &_mapping); _edge_mapping.clear_resize(edgeEnd()); _edge_mapping.fffill(); for (i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge &edge = mol.getEdge(i); _edge_mapping[findEdgeIndex(_inv_mapping[edge.beg], _inv_mapping[edge.end])] = i; } // Collect atom properties _collectAtomProperties(); // Detect distances from _atomsEmitBond elements to _atomsAcceptBond elements QS_DEF(Array<int>, distancesMatrix); distancesMatrix.resize(_atomsEmitBond.size() * _atomsAcceptBond.size()); for (int i = 0; i < _atomsEmitBond.size(); i++) { int *result = distancesMatrix.ptr() + _atomsAcceptBond.size() * i; _findMinDistance(_atomsEmitBond[i], 6, _atomsAcceptBond, result); } QS_DEF(Array<int>, attachedBonds); attachedBonds.clear(); for (int i = 0; i < _atomsEmitBond.size(); i++) for (int j = 0; j < _atomsAcceptBond.size(); j++) { int v1 = _atomsEmitBond[i]; int v2 = _atomsAcceptBond[j]; if (findEdgeIndex(v1, v2) != -1) continue; // Check new loop size: 5 or 6 int size = distancesMatrix[_atomsAcceptBond.size() * i + j]; if (size != 4 && size != 5) continue; attachedBonds.push(addEdge(v1, v2)); } _isBondAttachedArray.resize(edgeEnd()); _isBondAttachedArray.zerofill(); for (int i = 0; i < attachedBonds.size(); i++) _isBondAttachedArray[attachedBonds[i]] = true; _inside_ctor = false; } TautomerSuperStructure::~TautomerSuperStructure () { } void TautomerSuperStructure::clear () { if (_inside_ctor) Molecule::clear(); else throw Exception("clear(): not supported"); } int TautomerSuperStructure::getBondOrder (int idx) { if (!_inside_ctor && _isBondAttachedArray[idx]) return -1; return Molecule::getBondOrder(idx); } int TautomerSuperStructure::getBondTopology (int idx) { if (!_inside_ctor &&_isBondAttachedArray[idx]) return -1; return Molecule::getBondTopology(idx); } bool TautomerSuperStructure::possibleBondOrder (int idx, int order) { if (!_inside_ctor &&_isBondAttachedArray[idx]) return order == 0 || order == BOND_SINGLE; return Molecule::possibleBondOrder(idx, order); } int TautomerSuperStructure::getSubgraphType (const Array<int> &vertices, const Array<int> &edges) { // For any atoms number of attached bonds must be 0 or 1 QS_DEF(Array<int>, per_vertex_attached_bonds); per_vertex_attached_bonds.clear_resize(vertexEnd()); per_vertex_attached_bonds.zerofill(); int attached_bonds = 0; for (int i = 0; i < edges.size(); i++) { int edge_index = edges[i]; if (!_isBondAttachedArray[edge_index]) continue; const Edge &edge = getEdge(edge_index); per_vertex_attached_bonds[edge.beg]++; per_vertex_attached_bonds[edge.end]++; if (per_vertex_attached_bonds[edge.beg] > 1 || per_vertex_attached_bonds[edge.end] > 1) return NONE; attached_bonds++; } if (attached_bonds == 0) return ORIGINAL; return TAUTOMER; }
void CrfSaver::_writeMolecule (Molecule &molecule) { Obj<CmfSaver> saver; int i; if (_encoder.get() != 0) saver.create(_encoder.ref()); else saver.create(_output); QS_DEF(Array<int>, atom_flags); QS_DEF(Array<int>, bond_flags); if (_atom_stereo_flags != 0) { atom_flags.clear_resize(molecule.vertexEnd()); atom_flags.zerofill(); for (i = molecule.vertexBegin(); i != molecule.vertexEnd(); i = molecule.vertexNext(i)) if (_atom_stereo_flags[i] == STEREO_RETAINS) atom_flags[i] = 1; else if (_atom_stereo_flags[i] == STEREO_INVERTS) atom_flags[i] = 2; saver->atom_flags = atom_flags.ptr(); } if (_bond_rc_flags != 0) { bond_flags.clear_resize(molecule.edgeEnd()); bond_flags.zerofill(); for (i = molecule.edgeBegin(); i != molecule.edgeEnd(); i = molecule.edgeNext(i)) { if (_bond_rc_flags[i] & RC_UNCHANGED) bond_flags[i] |= 1; if (_bond_rc_flags[i] & RC_MADE_OR_BROKEN) bond_flags[i] |= 2; if (_bond_rc_flags[i] & RC_ORDER_CHANGED) bond_flags[i] |= 4; } saver->bond_flags = bond_flags.ptr(); } saver->save_bond_dirs = save_bond_dirs; saver->save_highlighting = save_highlighting; saver->save_mapping = save_mapping; saver->saveMolecule(molecule); if (_aam != 0) _writeAam(_aam, saver->getAtomSequence()); if (xyz_output != 0) { if (xyz_output == &_output && _encoder.get() != 0) _encoder->finish(); saver->saveXyz(*xyz_output); if (xyz_output == &_output && _encoder.get() != 0) _encoder->start(); } }
void convertMolfile (char *path, char *filename, FileOutput &cpp_file) { FileScanner molfile("%s\\%s", path, filename); MolfileLoader mf_loader(molfile); Molecule mol; QS_DEF(Array<int>, edges); printf("%s\n", filename); mf_loader.loadMolecule(mol, true); BiconnectedDecomposer bd(mol); if (bd.decompose() != 1) { printf("Error: %s is not biconnected\n", filename); return; } int i, j; edges.clear_reserve(mol.edgeCount()); for (i = mol.edgeBegin() ; i < mol.edgeEnd(); i = mol.edgeNext(i)) edges.push(i); edges.qsort(edge_cmp, &mol); const Edge &edge = mol.getEdge(edges[edges.size() / 2]); Vec3f v1 = mol.getAtomPos(edge.beg); Vec3f v2 = mol.getAtomPos(edge.end); v1.z = 0.f; v2.z = 0.f; float scale = Vec3f::dist(v1, v2); if (scale < 0.0001f) { printf("Error: %s has zero bond\n", filename); return; } scale = 1.f / scale; int first_idx = mol.vertexBegin(); Vec3f pos = mol.getAtomPos(first_idx); for (i = mol.vertexNext(first_idx); i < mol.vertexEnd(); i = mol.vertexNext(i)) { if (mol.getAtomPos(i).y < pos.y) { pos = mol.getAtomPos(i); first_idx = i; } } for (i = mol.vertexBegin() ; i < mol.vertexEnd(); i = mol.vertexNext(i)) { mol.getAtom2(i).pos.sub(pos); mol.getAtom2(i).pos.scale(scale); } char buf[1024]; sprintf_s(buf, "BEGIN_PATTERN(\"%s\")", filename); cpp_file.writeStringCR(buf); for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) { sprintf_s(buf, " ADD_ATOM(%d, %ff, %ff)", i, mol.getAtomPos(i).x, mol.getAtomPos(i).y); cpp_file.writeStringCR(buf); } for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge &edge = mol.getEdge(i); int type = mol.getBond(i).type; int qtype = mol.getQueryBond(i).type; sprintf_s(buf, " ADD_BOND(%d, %d, %d)", edge.beg, edge.end, qtype != 0 ? qtype : type); cpp_file.writeStringCR(buf); } Vec2f v, inter; Vec2f pos_i; int idx = mol.vertexCount(); i = first_idx; float max_angle, cur_angle; float i_angle = 0; int next_nei = 0; int point_idx = 0; pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y); while (true) { const Vertex &vert = mol.getVertex(i); if (i != first_idx) { v.set(pos_i.x, pos_i.y); pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y); v.sub(pos_i); i_angle = v.tiltAngle2(); } else if (point_idx > 0) break; sprintf_s(buf, " OUTLINE_POINT(%d, %ff, %ff)", point_idx++, pos_i.x, pos_i.y); cpp_file.writeStringCR(buf); max_angle = 0.f; for (j = vert.neiBegin(); j < vert.neiEnd(); j = vert.neiNext(j)) { const Vec3f &pos_nei = mol.getAtomPos(vert.neiVertex(j)); v.set(pos_nei.x - pos_i.x, pos_nei.y - pos_i.y); cur_angle = v.tiltAngle2() - i_angle; if (cur_angle < 0.f) cur_angle += 2 * PI; if (max_angle < cur_angle) { max_angle = cur_angle; next_nei = j; } } i = vert.neiVertex(next_nei); float dist, min_dist = 0.f; int int_edge; Vec2f cur_v1 = pos_i; Vec2f cur_v2(mol.getAtomPos(i).x, mol.getAtomPos(i).y); while (min_dist < 10000.f) { min_dist = 10001.f; for (j = mol.edgeBegin(); j < mol.edgeEnd(); j = mol.edgeNext(j)) { const Edge &edge = mol.getEdge(j); Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y); Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y); if (Vec2f::intersection(cur_v1, cur_v2, cur_v3, cur_v4, v)) if ((dist = Vec2f::dist(cur_v1, v)) < min_dist) { inter = v; min_dist = dist; int_edge = j; } } if (min_dist < 10000.f) { sprintf_s(buf, " OUTLINE_POINT(%d, %ff, %ff)", point_idx++, v.x, v.y); cpp_file.writeStringCR(buf); const Edge &edge = mol.getEdge(int_edge); Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y); Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y); Vec2f cur_v1v; Vec2f cur_v3v; Vec2f cur_v4v; cur_v1v.diff(cur_v1, inter); cur_v3v.diff(cur_v3, inter); cur_v4v.diff(cur_v4, inter); float angle1 = cur_v1v.tiltAngle2(); float angle3 = cur_v3v.tiltAngle2() - angle1; float angle4 = cur_v4v.tiltAngle2() - angle1; if (angle3 < 0) angle3 += 2 * PI; if (angle4 < 0) angle4 += 2 * PI; cur_v1 = inter; if (angle3 > angle4) { cur_v2 = cur_v3; i = edge.beg; } else { cur_v2 = cur_v4; i = edge.end; } } } } cpp_file.writeStringCR("END_PATTERN()"); }