Search in sources :

Example 6 with CoordinateInventor

use of com.actelion.research.chem.coords.CoordinateInventor in project openchemlib by Actelion.

the class JDrawArea method cleanupMoleculeCoordinates.

private void cleanupMoleculeCoordinates(Graphics g, ExtendedDepictor depictor, boolean selectedOnly) {
    if (mUpdateMode == UPDATE_INVENT_COORDS) {
        if (selectedOnly) {
            for (int atom = 0; atom < mMol.getAllAtoms(); atom++) {
                mMol.setAtomMarker(atom, !mMol.isSelectedAtom(atom));
            }
        }
        new CoordinateInventor(selectedOnly ? CoordinateInventor.MODE_KEEP_MARKED_ATOM_COORDS : 0).invent(mMol);
        mMol.setStereoBondsFromParity();
    }
    depictor.updateCoords(g, new Rectangle2D.Double(0, 0, getWidth(), getHeight()), maxUpdateMode());
}
Also used : CoordinateInventor(com.actelion.research.chem.coords.CoordinateInventor) Rectangle2D(java.awt.geom.Rectangle2D)

Example 7 with CoordinateInventor

use of com.actelion.research.chem.coords.CoordinateInventor in project openchemlib by Actelion.

the class SmilesParser method parse.

public void parse(StereoMolecule mol, byte[] smiles, int position, int endIndex, boolean createCoordinates, boolean readStereoFeatures) throws Exception {
    mMol = mol;
    mMol.deleteMolecule();
    TreeMap<Integer, THParity> parityMap = null;
    int[] baseAtom = new int[MAX_BRACKET_LEVELS];
    baseAtom[0] = -1;
    int[] ringClosureAtom = new int[MAX_RE_CONNECTIONS];
    int[] ringClosurePosition = new int[MAX_RE_CONNECTIONS];
    int[] ringClosureBondType = new int[MAX_RE_CONNECTIONS];
    for (int i = 0; i < MAX_RE_CONNECTIONS; i++) ringClosureAtom[i] = -1;
    int atomMass = 0;
    int fromAtom = -1;
    boolean squareBracketOpen = false;
    boolean percentFound = false;
    boolean smartsFeatureFound = false;
    int bracketLevel = 0;
    int bondType = Molecule.cBondTypeSingle;
    while (smiles[position] <= 32) position++;
    while (position < endIndex) {
        char theChar = (char) smiles[position++];
        if (Character.isLetter(theChar) || theChar == '*') {
            int atomicNo = 0;
            int explicitHydrogens = -1;
            boolean isWildCard = false;
            boolean parityFound = false;
            boolean isClockwise = false;
            if (squareBracketOpen) {
                if (theChar == 'R' && Character.isDigit(smiles[position])) {
                    int noOfDigits = Character.isDigit(smiles[position + 1]) ? 2 : 1;
                    atomicNo = Molecule.getAtomicNoFromLabel(new String(smiles, position - 1, 1 + noOfDigits));
                    position += noOfDigits;
                } else {
                    int labelLength = Character.isLowerCase(smiles[position]) ? 2 : 1;
                    atomicNo = Molecule.getAtomicNoFromLabel(new String(smiles, position - 1, labelLength));
                    position += labelLength - 1;
                    explicitHydrogens = 0;
                }
                if (smiles[position] == '@') {
                    position++;
                    if (smiles[position] == '@') {
                        isClockwise = true;
                        position++;
                    }
                    parityFound = true;
                }
                if (smiles[position] == 'H') {
                    position++;
                    explicitHydrogens = 1;
                    if (Character.isDigit(smiles[position])) {
                        explicitHydrogens = smiles[position] - '0';
                        position++;
                    }
                }
            } else if (theChar == '*') {
                atomicNo = 6;
                isWildCard = true;
            } else {
                switch(Character.toUpperCase(theChar)) {
                    case 'B':
                        if (position < endIndex && smiles[position] == 'r') {
                            atomicNo = 35;
                            position++;
                        } else
                            atomicNo = 5;
                        break;
                    case 'C':
                        if (position < endIndex && smiles[position] == 'l') {
                            atomicNo = 17;
                            position++;
                        } else
                            atomicNo = 6;
                        break;
                    case 'F':
                        atomicNo = 9;
                        break;
                    case 'I':
                        atomicNo = 53;
                        break;
                    case 'N':
                        atomicNo = 7;
                        break;
                    case 'O':
                        atomicNo = 8;
                        break;
                    case 'P':
                        atomicNo = 15;
                        break;
                    case 'S':
                        atomicNo = 16;
                        break;
                }
            }
            if (atomicNo == 0)
                throw new Exception("SmilesParser: unknown element label found");
            // this may be a hydrogen, if defined as [H]
            int atom = mMol.addAtom(atomicNo);
            if (isWildCard) {
                smartsFeatureFound = true;
                mMol.setAtomQueryFeature(atom, Molecule.cAtomQFAny, true);
            }
            // mark aromatic atoms
            if (Character.isLowerCase(theChar)) {
                mMol.setAtomMarker(atom, true);
                mAromaticAtoms++;
            } else {
                mMol.setAtomMarker(atom, false);
            }
            // put explicitHydrogen into atomCustomLabel to keep atom-relation when hydrogens move to end of atom list in handleHydrogen()
            if (explicitHydrogens != -1 && atomicNo != 1) {
                // no custom labels for hydrogen to get useful results in getHandleHydrogenMap()
                byte[] bytes = new byte[1];
                bytes[0] = (byte) explicitHydrogens;
                mMol.setAtomCustomLabel(atom, bytes);
            }
            fromAtom = baseAtom[bracketLevel];
            if (baseAtom[bracketLevel] != -1 && bondType != Molecule.cBondTypeDeleted) {
                mMol.addBond(atom, baseAtom[bracketLevel], bondType);
            }
            bondType = Molecule.cBondTypeSingle;
            baseAtom[bracketLevel] = atom;
            if (atomMass != 0) {
                mMol.setAtomMass(atom, atomMass);
                atomMass = 0;
            }
            if (readStereoFeatures) {
                THParity parity = (parityMap == null) ? null : parityMap.get(fromAtom);
                if (// if previous atom is a stereo center
                parity != null)
                    parity.addNeighbor(atom, position, atomicNo == 1 && atomMass == 0);
                if (parityFound) {
                    // if this atom is a stereo center
                    if (parityMap == null)
                        parityMap = new TreeMap<Integer, THParity>();
                    // using position as hydrogenPosition is close enough
                    parityMap.put(atom, new THParity(atom, fromAtom, explicitHydrogens, position, isClockwise));
                }
            }
            continue;
        }
        if (theChar == '.') {
            bondType = Molecule.cBondTypeDeleted;
            continue;
        }
        if (theChar == '=') {
            bondType = Molecule.cBondTypeDouble;
            continue;
        }
        if (theChar == '#') {
            bondType = Molecule.cBondTypeTriple;
            continue;
        }
        if (Character.isDigit(theChar)) {
            int number = theChar - '0';
            if (squareBracketOpen) {
                while (position < endIndex && Character.isDigit(smiles[position])) {
                    number = 10 * number + smiles[position] - '0';
                    position++;
                }
                atomMass = number;
            } else {
                boolean hasBondType = (smiles[position - 2] == '-' || smiles[position - 2] == '=' || smiles[position - 2] == '#' || smiles[position - 2] == ':');
                if (percentFound && position < endIndex && Character.isDigit(smiles[position])) {
                    number = 10 * number + smiles[position] - '0';
                    position++;
                }
                percentFound = false;
                if (number >= MAX_RE_CONNECTIONS)
                    throw new Exception("SmilesParser: ringClosureAtom number out of range");
                if (ringClosureAtom[number] == -1) {
                    ringClosureAtom[number] = baseAtom[bracketLevel];
                    ringClosurePosition[number] = position - 1;
                    ringClosureBondType[number] = hasBondType ? bondType : -1;
                } else {
                    if (ringClosureAtom[number] == baseAtom[bracketLevel])
                        throw new Exception("SmilesParser: ring closure to same atom");
                    if (readStereoFeatures && parityMap != null) {
                        THParity parity = parityMap.get(ringClosureAtom[number]);
                        if (parity != null)
                            parity.addNeighbor(baseAtom[bracketLevel], ringClosurePosition[number], false);
                        parity = parityMap.get(baseAtom[bracketLevel]);
                        if (parity != null)
                            parity.addNeighbor(ringClosureAtom[number], position - 1, false);
                    }
                    if (ringClosureBondType[number] != -1)
                        bondType = ringClosureBondType[number];
                    mMol.addBond(baseAtom[bracketLevel], ringClosureAtom[number], bondType);
                    // for number re-usage
                    ringClosureAtom[number] = -1;
                }
                bondType = Molecule.cBondTypeSingle;
            }
            continue;
        }
        if (theChar == '+') {
            if (!squareBracketOpen)
                throw new Exception("SmilesParser: '+' found outside brackets");
            int charge = 1;
            while (smiles[position] == '+') {
                charge++;
                position++;
            }
            if (charge == 1 && Character.isDigit(smiles[position])) {
                charge = smiles[position] - '0';
                position++;
            }
            mMol.setAtomCharge(baseAtom[bracketLevel], charge);
            continue;
        }
        if (theChar == '-') {
            if (!squareBracketOpen)
                // single bond
                continue;
            int charge = -1;
            while (smiles[position] == '-') {
                charge--;
                position++;
            }
            if (charge == -1 && Character.isDigit(smiles[position])) {
                charge = '0' - smiles[position];
                position++;
            }
            mMol.setAtomCharge(baseAtom[bracketLevel], charge);
            continue;
        }
        if (theChar == '(') {
            if (baseAtom[bracketLevel] == -1)
                throw new Exception("Smiles with leading parenthesis are not supported");
            baseAtom[bracketLevel + 1] = baseAtom[bracketLevel];
            bracketLevel++;
            continue;
        }
        if (theChar == ')') {
            bracketLevel--;
            continue;
        }
        if (theChar == '[') {
            if (squareBracketOpen)
                throw new Exception("SmilesParser: nested square brackets found");
            squareBracketOpen = true;
            continue;
        }
        if (theChar == ']') {
            if (!squareBracketOpen)
                throw new Exception("SmilesParser: closing bracket without opening one");
            squareBracketOpen = false;
            continue;
        }
        if (theChar == '%') {
            percentFound = true;
            continue;
        }
        if (theChar == ':') {
            if (!squareBracketOpen) {
                bondType = Molecule.cBondTypeDelocalized;
                continue;
            }
            int mapNo = 0;
            while (Character.isDigit(smiles[position])) {
                mapNo = 10 * mapNo + smiles[position] - '0';
                position++;
            }
            mMol.setAtomMapNo(baseAtom[bracketLevel], mapNo, false);
            continue;
        }
        if (theChar == '/') {
            if (readStereoFeatures)
                bondType = Molecule.cBondTypeUp;
            // encode slash temporarily in bondType
            continue;
        }
        if (theChar == '\\') {
            if (readStereoFeatures)
                bondType = Molecule.cBondTypeDown;
            // encode backslash temporarily in bondType
            continue;
        }
        if (theChar <= ' ') {
            // we stop reading at whitespace
            position = endIndex;
            continue;
        }
        throw new Exception("SmilesParser: unexpected character found: '" + theChar + "'");
    }
    // Check for unsatisfied open bonds
    if (bondType != Molecule.cBondTypeSingle)
        throw new Exception("SmilesParser: dangling open bond");
    for (int i = 0; i < MAX_RE_CONNECTIONS; i++) if (ringClosureAtom[i] != -1)
        throw new Exception("SmilesParser: dangling ring closure");
    int[] handleHydrogenAtomMap = mMol.getHandleHydrogenMap();
    // If the number of explicitly defined hydrogens conflicts with the occupied and default valence, then set an abnormal valence.
    // We may have a fragment. Therefore, prevent conversion of explicit H into a query feature.
    mMol.setHydrogenProtection(true);
    mMol.ensureHelperArrays(Molecule.cHelperNeighbours);
    for (int atom = 0; atom < mMol.getAllAtoms(); atom++) {
        if (mol.getAtomCustomLabel(atom) != null) {
            // if we have the exact number of hydrogens
            if (!mMol.isMarkedAtom(atom)) {
                // don't correct aromatic atoms
                int explicitHydrogen = mMol.getAtomCustomLabelBytes(atom)[0];
                if (mMol.getAtomicNo(atom) < Molecule.cAtomValence.length && Molecule.cAtomValence[mMol.getAtomicNo(atom)] != null) {
                    boolean compatibleValenceFound = false;
                    int usedValence = mMol.getOccupiedValence(atom);
                    usedValence -= mMol.getElectronValenceCorrection(atom, usedValence);
                    for (byte valence : Molecule.cAtomValence[mMol.getAtomicNo(atom)]) {
                        if (usedValence <= valence) {
                            compatibleValenceFound = true;
                            if (valence != usedValence + explicitHydrogen)
                                mMol.setAtomAbnormalValence(atom, usedValence + explicitHydrogen);
                            break;
                        }
                    }
                    if (!compatibleValenceFound)
                        mMol.setAtomAbnormalValence(atom, usedValence + explicitHydrogen);
                } else {
                    for (int i = 0; i < explicitHydrogen; i++) mol.addBond(atom, mol.addAtom(1), 1);
                }
            }
        }
    }
    mMol.ensureHelperArrays(Molecule.cHelperNeighbours);
    // convert pyridine oxides and nitro into polar structures with valid nitrogen valences
    correctValenceExceededNitrogen();
    locateAromaticDoubleBonds();
    mMol.removeAtomCustomLabels();
    mMol.setHydrogenProtection(false);
    if (readStereoFeatures) {
        if (resolveStereoBonds())
            mMol.setParitiesValid(0);
    }
    if (createCoordinates || readStereoFeatures) {
        new CoordinateInventor().invent(mMol);
        if (readStereoFeatures) {
            if (parityMap != null) {
                for (THParity parity : parityMap.values()) mMol.setAtomParity(parity.mCentralAtom, parity.calculateParity(handleHydrogenAtomMap), false);
                mMol.setParitiesValid(0);
            }
            mMol.setStereoBondsFromParity();
            mMol.setUnknownParitiesToExplicitlyUnknown();
        }
    }
    if (smartsFeatureFound)
        mMol.setFragment(true);
}
Also used : CoordinateInventor(com.actelion.research.chem.coords.CoordinateInventor) TreeMap(java.util.TreeMap)

Example 8 with CoordinateInventor

use of com.actelion.research.chem.coords.CoordinateInventor in project openchemlib by Actelion.

the class AtomHighlightAction method expandAtomKeyStrokes.

private void expandAtomKeyStrokes(StereoMolecule mol, int highliteAtom, String keyStrokes) {
    int atomicNo = Molecule.getAtomicNoFromLabel(keyStrokes);
    if (atomicNo != 0) {
        if (mol.changeAtom(highliteAtom, atomicNo, 0, -1, 0)) {
            model.changed();
            return;
        }
    }
    StereoMolecule substituent = NamedSubstituents.getSubstituent(keyStrokes);
    if (substituent != null) {
        // Copy the the fragment containing the attachment point into a new molecule.
        // Then attach the substituent, create new atom coordinates for the substituent,
        // while retaining coordinates of the fragment.
        StereoMolecule fragment = new StereoMolecule();
        fragment.addFragment(mol, highliteAtom, null);
        double sourceAVBL = fragment.getAverageBondLength();
        int firstAtomInFragment = fragment.getAllAtoms();
        for (int atom = 0; atom < fragment.getAllAtoms(); atom++) {
            fragment.setAtomMarker(atom, true);
        }
        fragment.addSubstituent(substituent, 0);
        new CoordinateInventor(CoordinateInventor.MODE_KEEP_MARKED_ATOM_COORDS).invent(fragment);
        double dx = mol.getAtomX(highliteAtom) - sourceAVBL * fragment.getAtomX(0);
        double dy = mol.getAtomY(highliteAtom) - sourceAVBL * fragment.getAtomY(0);
        // Attach the substituent to the complete molecule and take coodinates from the
        // previously created fragment-substituent species.
        int firstAtomInMol = mol.getAllAtoms();
        mol.addSubstituent(substituent, highliteAtom);
        int substituentAtoms = mol.getAllAtoms() - firstAtomInMol;
        for (int i = 0; i < substituentAtoms; i++) {
            mol.setAtomX(firstAtomInMol + i, sourceAVBL * fragment.getAtomX(firstAtomInFragment + i) + dx);
            mol.setAtomY(firstAtomInMol + i, sourceAVBL * fragment.getAtomY(firstAtomInFragment + i) + dy);
        }
        mol.setStereoBondsFromParity();
        model.changed();
    }
}
Also used : CoordinateInventor(com.actelion.research.chem.coords.CoordinateInventor) StereoMolecule(com.actelion.research.chem.StereoMolecule)

Example 9 with CoordinateInventor

use of com.actelion.research.chem.coords.CoordinateInventor in project openchemlib by Actelion.

the class Model method cleanupMoleculeCoordinates.

private void cleanupMoleculeCoordinates(AbstractDepictor depictor, boolean invent, boolean selectedOnly) {
    // if (mUpdateMode == UPDATE_INVENT_COORDS)
    if (invent) {
        if (selectedOnly) {
            for (int atom = 0; atom < mMol.getAllAtoms(); atom++) {
                mMol.setAtomMarker(atom, !mMol.isSelectedAtom(atom));
            }
        }
        new CoordinateInventor(selectedOnly ? CoordinateInventor.MODE_KEEP_MARKED_ATOM_COORDS : 0).invent(mMol);
        mMol.setStereoBondsFromParity();
    }
    DepictorTransformation dt = depictor.simpleValidateView(new Rectangle2D.Double(0, 0, this.getWidth(), this.getHeight()), AbstractDepictor.cModeInflateToMaxAVBL);
    if (dt != null)
        dt.applyTo(mMol);
}
Also used : CoordinateInventor(com.actelion.research.chem.coords.CoordinateInventor) Rectangle2D(java.awt.geom.Rectangle2D)

Aggregations

CoordinateInventor (com.actelion.research.chem.coords.CoordinateInventor)9 Rectangle2D (java.awt.geom.Rectangle2D)4 StereoMolecule (com.actelion.research.chem.StereoMolecule)1 ReactionArrow (com.actelion.research.chem.reaction.ReactionArrow)1 TreeMap (java.util.TreeMap)1