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());
}
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);
}
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();
}
}
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);
}
Aggregations