private void assignStereochem(IAtomContainer molecule) { // XXX: can't check this unless we store 'unspecified' double bonds // if (!molecule.stereoElements().iterator().hasNext()) // return; // assign up/down labels, this doesn't not alter layout and could be // done on-demand (e.g. when writing a MDL Molfile) NonplanarBonds.assign(molecule); }
/** * Assign non-planar, up and down labels to indicate tetrahedral configuration. Currently all * existing directional labels are removed before assigning new labels. * * @param container the structure to assign labels to * @return a container with assigned labels (currently the same as the input) * @throws IllegalArgumentException an atom had no 2D coordinates or labels could not be * assigned to a tetrahedral centre */ public static IAtomContainer assign(final IAtomContainer container) { GraphUtil.EdgeToBondMap edgeToBond = GraphUtil.EdgeToBondMap.withSpaceFor(container); new NonplanarBonds(container, GraphUtil.toAdjList(container, edgeToBond), edgeToBond); return container; }
private boolean assignTwoLabels(IBond[] bonds, IBond.Stereo[] labels) { return labels.length == 4 && countRingBonds(bonds) != 3; }
Point2d ref = new Point2d(fp.x, fp.y+blen); snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(-60))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(-120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(120))); snapBondToPosition(focus, bonds.get(5), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, DOWN); setBondDisplay(bonds.get(2), focus, DOWN); setBondDisplay(bonds.get(3), focus, UP); setBondDisplay(bonds.get(4), focus, UP);
boolean mirror = doMirror(atoms.subList(1,4)); snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(-60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(90))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(-120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, UP); setBondDisplay(bonds.get(3), focus, DOWN); } else { snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(-90))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, DOWN); setBondDisplay(bonds.get(3), focus, UP);
final IBond[] bonds = new IBond[4]; int p = parity(element.winding()); bonds[i] = findBond(left, right, atoms[i]); for (int i = 0; i < 4; i++) rank[i] = i; p *= sortClockwise(rank, focus, atoms, 4); for (int v : priority(atomToIndex.get(focus), atoms, 4)) { IBond bond = bonds[v]; if (bond == null) continue; setWedge(bonds[0], atoms[0], labels[0]); if (priority[1] < 5) setWedge(bonds[1], atoms[1], labels[1]); } else { if (priority[2] < 5) setWedge(bonds[2], atoms[2], labels[2]); if (priority[3] < 5) setWedge(bonds[3], atoms[3], labels[3]);
final IBond[] bonds = new IBond[4]; int p = parity(element.getStereo()); int n = 0; p *= indexParity(i); // implicit H, adjust parity } else { bonds[n] = container.getBond(focus, atoms[i]); for (int i = 0; i < n; i++) rank[i] = i; p *= sortClockwise(rank, focus, atoms, n); boolean assignTwoLabels = assignTwoLabels(bonds, labels); for (int v : priority(atomToIndex.get(focus), atoms, n)) { IBond bond = bonds[v]; if (bond.getStereo() != NONE || bond.getOrder() != SINGLE) if (isSp3Carbon(atoms[v], graph[container.indexOf(atoms[v])].length)) break; bond.setAtoms(new IAtom[]{focus, atoms[v]}); // avoids UP_INVERTED/DOWN_INVERTED
label(tetrahedralElements[foci[i]]); label((ExtendedTetrahedral) se); } else if (se instanceof Atropisomeric) { label((Atropisomeric) se); } else if (se instanceof SquarePlanar) { modifyAndLabel((SquarePlanar) se); } else if (se instanceof TrigonalBipyramidal) { modifyAndLabel((TrigonalBipyramidal) se); } else if (se instanceof Octahedral) { modifyAndLabel((Octahedral) se); for (IBond bond : findUnspecifiedDoubleBonds(g)) { labelUnspecified(bond);
private void setBondDisplay(IBond bond, IAtom focus, IBond.Stereo display) { if (bond.getBegin().equals(focus)) bond.setStereo(display); else bond.setStereo(flip(display)); }
/** * Checks if the atom can be involved in a double-bond. * @param idx atom idx * @return the atom at index (idx) is valid for a double bond * @see <a href="http://www.inchi-trust.org/download/104/InChI_TechMan.pdf">Double bond stereochemistry, InChI Technical Manual</a> */ private boolean isCisTransEndPoint(int idx){ IAtom atom = container.getAtom(idx); // error: uninit atom if (atom.getAtomicNumber() == null || atom.getFormalCharge() == null || atom.getImplicitHydrogenCount() == null) return false; final int chg = atom.getFormalCharge(); final int btypes = getBondTypes(idx); switch (atom.getAtomicNumber()) { case 6: // C case 14: // Si case 32: // Ge // double, single, single return chg == 0 && btypes == 0x0102; case 7: // N if (chg == 0) // double, single return btypes == 0x0101; if (chg == +1) // double, single, single return btypes == 0x0102; default: return false; } }
final IBond[] bonds = new IBond[4]; int p = parity(element.getStereo()); int n = 0; p *= indexParity(i); // implicit H, adjust parity } else { bonds[n] = container.getBond(focus, atoms[i]); for (int i = 0; i < n; i++) rank[i] = i; p *= sortClockwise(rank, focus, atoms, n); boolean assignTwoLabels = assignTwoLabels(bonds, labels); for (int v : priority(atomToIndex.get(focus), atoms, n)) { IBond bond = bonds[v]; if (bond.getStereo() != NONE || bond.getOrder() != SINGLE) if (isSp3Carbon(atoms[v], graph[container.indexOf(atoms[v])].length)) break; bond.setAtoms(new IAtom[]{focus, atoms[v]}); // avoids UP_INVERTED/DOWN_INVERTED
final IBond[] bonds = new IBond[4]; int p = parity(element.winding()); bonds[i] = findBond(left, right, atoms[i]); for (int i = 0; i < 4; i++) rank[i] = i; p *= sortClockwise(rank, focus, atoms, 4); for (int v : priority(atomToIndex.get(focus), atoms, 4)) { IBond bond = bonds[v]; if (bond == null) continue; setWedge(bonds[0], atoms[0], labels[0]); if (priority[1] < 5) setWedge(bonds[1], atoms[1], labels[1]); } else { if (priority[2] < 5) setWedge(bonds[2], atoms[2], labels[2]); if (priority[3] < 5) setWedge(bonds[3], atoms[3], labels[3]);
Point2d ref = new Point2d(fp.x, fp.y+blen); snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(-60))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(-120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(120))); snapBondToPosition(focus, bonds.get(5), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, DOWN); setBondDisplay(bonds.get(2), focus, DOWN); setBondDisplay(bonds.get(3), focus, UP); setBondDisplay(bonds.get(4), focus, UP);
boolean mirror = doMirror(atoms.subList(1,4)); snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(-60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(90))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(-120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, UP); setBondDisplay(bonds.get(3), focus, DOWN); } else { snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(0))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(-90))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(120))); snapBondToPosition(focus, bonds.get(4), getRotated(ref, fp, Math.toRadians(180))); setBondDisplay(bonds.get(1), focus, DOWN); setBondDisplay(bonds.get(3), focus, UP);
label(tetrahedralElements[foci[i]]); label((ExtendedTetrahedral) se); } else if (se instanceof Atropisomeric) { label((Atropisomeric) se); } else if (se instanceof SquarePlanar) { modifyAndLabel((SquarePlanar) se); } else if (se instanceof TrigonalBipyramidal) { modifyAndLabel((TrigonalBipyramidal) se); } else if (se instanceof Octahedral) { modifyAndLabel((Octahedral) se); for (IBond bond : findUnspecifiedDoubleBonds(g)) { labelUnspecified(bond);
private void setBondDisplay(IBond bond, IAtom focus, IBond.Stereo display) { if (bond.getBegin().equals(focus)) bond.setStereo(display); else bond.setStereo(flip(display)); }
/** * Checks if the atom can be involved in a double-bond. * @param idx atom idx * @return the atom at index (idx) is valid for a double bond * @see <a href="http://www.inchi-trust.org/download/104/InChI_TechMan.pdf">Double bond stereochemistry, InChI Technical Manual</a> */ private boolean isCisTransEndPoint(int idx){ IAtom atom = container.getAtom(idx); // error: uninit atom if (atom.getAtomicNumber() == null || atom.getFormalCharge() == null || atom.getImplicitHydrogenCount() == null) return false; final int chg = atom.getFormalCharge(); final int btypes = getBondTypes(idx); switch (atom.getAtomicNumber()) { case 6: // C case 14: // Si case 32: // Ge // double, single, single return chg == 0 && btypes == 0x0102; case 7: // N if (chg == 0) // double, single return btypes == 0x0101; if (chg == +1) // double, single, single return btypes == 0x0102; default: return false; } }
private void assignStereochem(IAtomContainer molecule) { // XXX: can't check this unless we store 'unspecified' double bonds // if (!molecule.stereoElements().iterator().hasNext()) // return; // assign up/down labels, this doesn't not alter layout and could be // done on-demand (e.g. when writing a MDL Molfile) NonplanarBonds.assign(molecule); }
private void modifyAndLabel(SquarePlanar se) { List<IAtom> atoms = se.normalize().getCarriers(); List<IBond> bonds = new ArrayList<>(4); double blen = 0; for (IAtom atom : atoms) { IBond bond = container.getBond(se.getFocus(), atom); // can't handled these using this method! if (bond.isInRing()) return; bonds.add(bond); blen += GeometryUtil.getLength2D(bond); } blen /= bonds.size(); IAtom focus = se.getFocus(); Point2d fp = focus.getPoint2d(); for (IAtom atom : container.atoms()) atom.setFlag(CDKConstants.VISITED, false); for (IBond bond : container.bonds()) bond.setFlag(CDKConstants.VISITED, false); Point2d ref = new Point2d(fp.x, fp.y+blen); snapBondToPosition(focus, bonds.get(0), getRotated(ref, fp, Math.toRadians(-60))); snapBondToPosition(focus, bonds.get(1), getRotated(ref, fp, Math.toRadians(60))); snapBondToPosition(focus, bonds.get(2), getRotated(ref, fp, Math.toRadians(120))); snapBondToPosition(focus, bonds.get(3), getRotated(ref, fp, Math.toRadians(-120))); setBondDisplay(bonds.get(0), focus, DOWN); setBondDisplay(bonds.get(1), focus, DOWN); setBondDisplay(bonds.get(2), focus, UP); setBondDisplay(bonds.get(3), focus, UP); }
private boolean assignTwoLabels(IBond[] bonds, IBond.Stereo[] labels) { return labels.length == 4 && countRingBonds(bonds) != 3; }