/** * Returns the ring that is formed by the atoms in the given vector. * * @param vec The vector that contains the atoms of the ring * @param mol The molecule this ring is a substructure of * @return The ring formed by the given atoms */ private IRing prepareRing(List vec, IAtomContainer mol) { // add the atoms in vec to the new ring int atomCount = vec.size(); IRing ring = mol.getBuilder().newInstance(IRing.class, atomCount); IAtom[] atoms = new IAtom[atomCount]; vec.toArray(atoms); ring.setAtoms(atoms); // add the bonds in mol to the new ring try { IBond b; for (int i = 0; i < atomCount - 1; i++) { b = mol.getBond(atoms[i], atoms[i + 1]); if (b != null) { ring.addBond(b); } else { logger.error("This should not happen."); } } b = mol.getBond(atoms[0], atoms[atomCount - 1]); if (b != null) { ring.addBond(b); } else { logger.error("This should not happen either."); } } catch (Exception exc) { logger.debug(exc); } logger.debug("found Ring ", ring); return ring; }
/** * Convenience method for giving a string representation of this ring based on the number of the * atom in a given molecule. * * @param molecule A molecule to determine an atom number for each ring atom * @return string representation of this ring */ private String toString(IRing ring, IAtomContainer molecule) throws Exception { String str = ""; for (int f = 0; f < ring.getAtomCount(); f++) { str += molecule.getAtomNumber(ring.getAtom(f)) + " - "; } return str; }
@Test public void testCalculateMissingHydrogens_Aromatic() throws Exception { IAtomContainer pyrrole = MoleculeFactory.makePyrrole(); IAtom n = pyrrole.getAtom(1); IRingSet rs = (new SSSRFinder(pyrrole)).findSSSR(); IRing ring = (IRing) rs.getAtomContainer(0); for (int j = 0; j < ring.getBondCount(); j++) { ring.getBond(j).setFlag(CDKConstants.ISAROMATIC, true); } Assert.assertEquals(5, ring.getBondCount()); Assert.assertEquals(1, satcheck.calculateNumberOfImplicitHydrogens(n, pyrrole)); }
/** * Generated coordinates for a given ring, which is connected to a spiro ring. The rings share * exactly one atom. * * @param ring The ring to be placed * @param sharedAtoms The atoms of this ring, also members of another ring, which are already * placed * @param sharedAtomsCenter The geometric center of these atoms * @param ringCenterVector A vector pointing the the center of the new ring * @param bondLength The standard bondlength */ public void placeSpiroRing( IRing ring, IAtomContainer sharedAtoms, Point2d sharedAtomsCenter, Vector2d ringCenterVector, double bondLength) { logger.debug("placeSpiroRing"); double radius = getNativeRingRadius(ring, bondLength); Point2d ringCenter = new Point2d(sharedAtomsCenter); ringCenterVector.normalize(); ringCenterVector.scale(radius); ringCenter.add(ringCenterVector); double addAngle = 2 * Math.PI / ring.getRingSize(); IAtom startAtom = sharedAtoms.getAtom(0); // double centerX = ringCenter.x; // double centerY = ringCenter.y; // int direction = 1; IAtom currentAtom = startAtom; double startAngle = GeometryTools.getAngle( startAtom.getPoint2d().x - ringCenter.x, startAtom.getPoint2d().y - ringCenter.y); /* * Get one bond connected to the spiro bridge atom. * It doesn't matter in which direction we draw. */ java.util.List bonds = ring.getConnectedBondsList(startAtom); IBond currentBond = (IBond) bonds.get(0); Vector atomsToDraw = new Vector(); /* * Store all atoms to draw in consequtive order relative to the * chosen bond. */ for (int i = 0; i < ring.getBondCount(); i++) { currentBond = ring.getNextBond(currentBond, currentAtom); currentAtom = currentBond.getConnectedAtom(currentAtom); atomsToDraw.addElement(currentAtom); } logger.debug("currentAtom " + currentAtom); logger.debug("startAtom " + startAtom); atomPlacer.populatePolygonCorners(atomsToDraw, ringCenter, startAngle, addAngle, radius); }
/** * Walks throught the atoms of each ring in a ring set and marks a ring as PLACED if all of its * atoms have been placed. * * @param rs The ringset to be checked */ public void checkAndMarkPlaced(IRingSet rs) { IRing ring = null; boolean allPlaced = true; for (int i = 0; i < rs.getAtomContainerCount(); i++) { ring = (IRing) rs.getAtomContainer(i); allPlaced = true; for (int j = 0; j < ring.getAtomCount(); j++) { if (!((IAtom) ring.getAtom(j)).getFlag(CDKConstants.ISPLACED)) { allPlaced = false; break; } } ring.setFlag(CDKConstants.ISPLACED, allPlaced); } }
/** * Layout all rings in the given RingSet that are connected to a given Ring * * @param rs The RingSet to be searched for rings connected to Ring * @param ring The Ring for which all connected rings in RingSet are to be layed out. */ void placeConnectedRings(IRingSet rs, IRing ring, int handleType, double bondLength) { IRingSet connectedRings = rs.getConnectedRings(ring); IRing connectedRing; IAtomContainer sharedAtoms; int sac; Point2d oldRingCenter, sharedAtomsCenter, tempPoint; Vector2d tempVector, oldRingCenterVector, newRingCenterVector; // logger.debug(rs.reportRingList(molecule)); for (IAtomContainer container : connectedRings.atomContainers()) { connectedRing = (IRing) container; if (!connectedRing.getFlag(CDKConstants.ISPLACED)) { // logger.debug(ring.toString(molecule)); // logger.debug(connectedRing.toString(molecule)); sharedAtoms = AtomContainerManipulator.getIntersection(ring, connectedRing); sac = sharedAtoms.getAtomCount(); logger.debug("placeConnectedRings-> connectedRing: " + (ring.toString())); if ((sac == 2 && handleType == FUSED) || (sac == 1 && handleType == SPIRO) || (sac > 2 && handleType == BRIDGED)) { sharedAtomsCenter = GeometryTools.get2DCenter(sharedAtoms); oldRingCenter = GeometryTools.get2DCenter(ring); tempVector = (new Vector2d(sharedAtomsCenter)); newRingCenterVector = new Vector2d(tempVector); newRingCenterVector.sub(new Vector2d(oldRingCenter)); oldRingCenterVector = new Vector2d(newRingCenterVector); logger.debug( "placeConnectedRing -> tempVector: " + tempVector + ", tempVector.length: " + tempVector.length()); logger.debug("placeConnectedRing -> bondCenter: " + sharedAtomsCenter); logger.debug( "placeConnectedRing -> oldRingCenterVector.length(): " + oldRingCenterVector.length()); logger.debug( "placeConnectedRing -> newRingCenterVector.length(): " + newRingCenterVector.length()); tempPoint = new Point2d(sharedAtomsCenter); tempPoint.add(newRingCenterVector); placeRing(connectedRing, sharedAtoms, sharedAtomsCenter, newRingCenterVector, bondLength); connectedRing.setFlag(CDKConstants.ISPLACED, true); placeConnectedRings(rs, connectedRing, handleType, bondLength); } } } }
/** * Fixes Aromaticity of the molecule i.e. need to find rings and aromaticity again since added H's * * @param mol */ @TestMethod("testFixAromaticity") public static void configure(IAtomContainer mol) { // need to find rings and aromaticity again since added H's IRingSet ringSet = null; try { AllRingsFinder arf = new AllRingsFinder(); ringSet = arf.findAllRings(mol); } catch (Exception e) { e.printStackTrace(); } try { // figure out which atoms are in aromatic rings: CDKHydrogenAdder cdk = CDKHydrogenAdder.getInstance(DefaultChemObjectBuilder.getInstance()); cdk.addImplicitHydrogens(mol); ExtAtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(mol); CDKHueckelAromaticityDetector.detectAromaticity(mol); // figure out which rings are aromatic: RingSetManipulator.markAromaticRings(ringSet); // figure out which simple (non cycles) rings are aromatic: // only atoms in 6 membered rings are aromatic // determine largest ring that each atom is a part of for (int i = 0; i < mol.getAtomCount(); i++) { mol.getAtom(i).setFlag(CDKConstants.ISAROMATIC, false); jloop: for (int j = 0; j < ringSet.getAtomContainerCount(); j++) { // logger.debug(i+"\t"+j); IRing ring = (IRing) ringSet.getAtomContainer(j); if (!ring.getFlag(CDKConstants.ISAROMATIC)) { continue jloop; } boolean haveatom = ring.contains(mol.getAtom(i)); // logger.debug("haveatom="+haveatom); if (haveatom && ring.getAtomCount() == 6) { mol.getAtom(i).setFlag(CDKConstants.ISAROMATIC, true); } } } } catch (Exception e) { e.printStackTrace(); } }
/** * Selects an optimum edge for elimination in structures without N2 nodes. * * <p>This might be severely broken! Would have helped if there was an explanation of how this * algorithm worked. * * @param ring * @param molecule */ private IBond checkEdges(IRing ring, IAtomContainer molecule) { IRing r1, r2; IRingSet ringSet = ring.getBuilder().newInstance(IRingSet.class); IBond bond; int minMaxSize = Integer.MAX_VALUE; int minMax = 0; logger.debug("Molecule: " + molecule); Iterator<IBond> bonds = ring.bonds().iterator(); while (bonds.hasNext()) { bond = (IBond) bonds.next(); molecule.removeElectronContainer(bond); r1 = getRing(bond.getAtom(0), molecule); r2 = getRing(bond.getAtom(1), molecule); logger.debug("checkEdges: " + bond); if (r1.getAtomCount() > r2.getAtomCount()) { ringSet.addAtomContainer(r1); } else { ringSet.addAtomContainer(r2); } molecule.addBond(bond); } for (int i = 0; i < ringSet.getAtomContainerCount(); i++) { if (((IRing) ringSet.getAtomContainer(i)).getBondCount() < minMaxSize) { minMaxSize = ((IRing) ringSet.getAtomContainer(i)).getBondCount(); minMax = i; } } return (IBond) ring.getElectronContainer(minMax); }
/** * Calculated the center for the first ring so that it can layed out. Only then, all other rings * can be assigned coordinates relative to it. * * @param ring The ring for which the center is to be calculated * @return A Vector2d pointing to the new ringcenter */ Vector2d getRingCenterOfFirstRing(IRing ring, Vector2d bondVector, double bondLength) { int size = ring.getAtomCount(); double radius = bondLength / (2 * Math.sin((Math.PI) / size)); double newRingPerpendicular = Math.sqrt(Math.pow(radius, 2) - Math.pow(bondLength / 2, 2)); /* get the angle between the x axis and the bond vector */ double rotangle = GeometryTools.getAngle(bondVector.x, bondVector.y); /* Add 90 Degrees to this angle, this is supposed to be the new ringcenter vector */ rotangle += Math.PI / 2; return new Vector2d( Math.cos(rotangle) * newRingPerpendicular, Math.sin(rotangle) * newRingPerpendicular); }
/** * Partition the bonding partners of a given atom into ring atoms and non-ring atoms * * @param atom The atom whose bonding partners are to be partitioned * @param ring The ring against which the bonding partners are checked * @param ringAtoms An AtomContainer to store the ring bonding partners * @param nonRingAtoms An AtomContainer to store the non-ring bonding partners */ public void partitionNonRingPartners( IAtom atom, IRing ring, IAtomContainer ringAtoms, IAtomContainer nonRingAtoms) { java.util.List atoms = molecule.getConnectedAtomsList(atom); for (int i = 0; i < atoms.size(); i++) { IAtom curAtom = (IAtom) atoms.get(i); if (!ring.contains(curAtom)) { nonRingAtoms.addAtom(curAtom); } else { ringAtoms.addAtom(curAtom); } } }
/** * Positions the aliphatic substituents of a ring system * * @param rs The RingSystem for which the substituents are to be laid out * @return A list of atoms that where laid out */ public IAtomContainer placeRingSubstituents(IRingSet rs, double bondLength) { logger.debug("RingPlacer.placeRingSubstituents() start"); IRing ring = null; IAtom atom = null; IRingSet rings = null; IAtomContainer unplacedPartners = rs.getBuilder().newInstance(IAtomContainer.class); IAtomContainer sharedAtoms = rs.getBuilder().newInstance(IAtomContainer.class); IAtomContainer primaryAtoms = rs.getBuilder().newInstance(IAtomContainer.class); IAtomContainer treatedAtoms = rs.getBuilder().newInstance(IAtomContainer.class); Point2d centerOfRingGravity = null; for (int j = 0; j < rs.getAtomContainerCount(); j++) { ring = (IRing) rs.getAtomContainer(j); /* Get the j-th Ring in RingSet rs */ for (int k = 0; k < ring.getAtomCount(); k++) { unplacedPartners.removeAllElements(); sharedAtoms.removeAllElements(); primaryAtoms.removeAllElements(); atom = ring.getAtom(k); rings = rs.getRings(atom); centerOfRingGravity = GeometryTools.get2DCenter(rings); atomPlacer.partitionPartners(atom, unplacedPartners, sharedAtoms); atomPlacer.markNotPlaced(unplacedPartners); try { for (int f = 0; f < unplacedPartners.getAtomCount(); f++) { logger.debug( "placeRingSubstituents->unplacedPartners: " + (molecule.getAtomNumber(unplacedPartners.getAtom(f)) + 1)); } } catch (Exception exc) { } treatedAtoms.add(unplacedPartners); if (unplacedPartners.getAtomCount() > 0) { atomPlacer.distributePartners( atom, sharedAtoms, centerOfRingGravity, unplacedPartners, bondLength); } } } logger.debug("RingPlacer.placeRingSubstituents() end"); return treatedAtoms; }
/** * Place ring with user provided angles. * * @param ring the ring to place. * @param ringCenter center coordinates of the ring. * @param bondLength given bond length. * @param startAngles a map with start angles when drawing the ring. */ public void placeRing( IRing ring, Point2d ringCenter, double bondLength, Map<Integer, Double> startAngles) { double radius = this.getNativeRingRadius(ring, bondLength); double addAngle = 2 * Math.PI / ring.getRingSize(); IAtom startAtom = ring.getFirstAtom(); Point2d p = new Point2d(ringCenter.x + radius, ringCenter.y); startAtom.setPoint2d(p); double startAngle = Math.PI * 0.5; /* Different ring sizes get different start angles to have * visually correct placement */ int ringSize = ring.getRingSize(); if (startAngles.get(ringSize) != null) startAngle = startAngles.get(ringSize); List<IBond> bonds = ring.getConnectedBondsList(startAtom); /* * Store all atoms to draw in consecutive order relative to the * chosen bond. */ Vector<IAtom> atomsToDraw = new Vector<IAtom>(); IAtom currentAtom = startAtom; IBond currentBond = (IBond) bonds.get(0); for (int i = 0; i < ring.getBondCount(); i++) { currentBond = ring.getNextBond(currentBond, currentAtom); currentAtom = currentBond.getConnectedAtom(currentAtom); atomsToDraw.addElement(currentAtom); } atomPlacer.populatePolygonCorners(atomsToDraw, ringCenter, startAngle, addAngle, radius); }
/** * Returns the ring radius of a perfect polygons of size ring.getAtomCount() The ring radius is * the distance of each atom to the ringcenter. * * @param ring The ring for which the radius is to calculated * @param bondLength The bond length for each bond in the ring * @return The radius of the ring. */ public double getNativeRingRadius(IRing ring, double bondLength) { int size = ring.getAtomCount(); double radius = bondLength / (2 * Math.sin((Math.PI) / size)); return radius; }
/** * Generated coordinates for a given ring, which is fused to another ring. The rings share exactly * one bond. * * @param ring The ring to be placed * @param sharedAtoms The atoms of this ring, also members of another ring, which are already * placed * @param sharedAtomsCenter The geometric center of these atoms * @param ringCenterVector A vector pointing the the center of the new ring * @param bondLength The standard bondlength */ public void placeFusedRing( IRing ring, IAtomContainer sharedAtoms, Point2d sharedAtomsCenter, Vector2d ringCenterVector, double bondLength) { logger.debug("RingPlacer.placeFusedRing() start"); Point2d ringCenter = new Point2d(sharedAtomsCenter); double radius = getNativeRingRadius(ring, bondLength); double newRingPerpendicular = Math.sqrt(Math.pow(radius, 2) - Math.pow(bondLength / 2, 2)); ringCenterVector.normalize(); logger.debug("placeFusedRing->: ringCenterVector.length()" + ringCenterVector.length()); ringCenterVector.scale(newRingPerpendicular); ringCenter.add(ringCenterVector); IAtom bondAtom1 = sharedAtoms.getAtom(0); IAtom bondAtom2 = sharedAtoms.getAtom(1); Vector2d bondAtom1Vector = new Vector2d(bondAtom1.getPoint2d()); Vector2d bondAtom2Vector = new Vector2d(bondAtom2.getPoint2d()); Vector2d originRingCenterVector = new Vector2d(ringCenter); bondAtom1Vector.sub(originRingCenterVector); bondAtom2Vector.sub(originRingCenterVector); double occupiedAngle = bondAtom1Vector.angle(bondAtom2Vector); double remainingAngle = (2 * Math.PI) - occupiedAngle; double addAngle = remainingAngle / (ring.getRingSize() - 1); logger.debug("placeFusedRing->occupiedAngle: " + Math.toDegrees(occupiedAngle)); logger.debug("placeFusedRing->remainingAngle: " + Math.toDegrees(remainingAngle)); logger.debug("placeFusedRing->addAngle: " + Math.toDegrees(addAngle)); IAtom startAtom; double centerX = ringCenter.x; double centerY = ringCenter.y; double xDiff = bondAtom1.getPoint2d().x - bondAtom2.getPoint2d().x; double yDiff = bondAtom1.getPoint2d().y - bondAtom2.getPoint2d().y; double startAngle; ; int direction = 1; // if bond is vertical if (xDiff == 0) { logger.debug("placeFusedRing->Bond is vertical"); // starts with the lower Atom if (bondAtom1.getPoint2d().y > bondAtom2.getPoint2d().y) { startAtom = bondAtom1; } else { startAtom = bondAtom2; } // changes the drawing direction if (centerX < bondAtom1.getPoint2d().x) { direction = 1; } else { direction = -1; } } // if bond is not vertical else { // starts with the left Atom if (bondAtom1.getPoint2d().x > bondAtom2.getPoint2d().x) { startAtom = bondAtom1; } else { startAtom = bondAtom2; } // changes the drawing direction if (centerY - bondAtom1.getPoint2d().y > (centerX - bondAtom1.getPoint2d().x) * yDiff / xDiff) { direction = 1; } else { direction = -1; } } startAngle = GeometryTools.getAngle( startAtom.getPoint2d().x - ringCenter.x, startAtom.getPoint2d().y - ringCenter.y); IAtom currentAtom = startAtom; // determine first bond in Ring // int k = 0; // for (k = 0; k < ring.getElectronContainerCount(); k++) { // if (ring.getElectronContainer(k) instanceof IBond) break; // } IBond currentBond = sharedAtoms.getBond(0); Vector atomsToDraw = new Vector(); for (int i = 0; i < ring.getBondCount() - 2; i++) { currentBond = ring.getNextBond(currentBond, currentAtom); currentAtom = currentBond.getConnectedAtom(currentAtom); atomsToDraw.addElement(currentAtom); } addAngle = addAngle * direction; try { logger.debug("placeFusedRing->startAngle: " + Math.toDegrees(startAngle)); logger.debug("placeFusedRing->addAngle: " + Math.toDegrees(addAngle)); logger.debug("placeFusedRing->startAtom is: " + (molecule.getAtomNumber(startAtom) + 1)); logger.debug("AtomsToDraw: " + atomPlacer.listNumbers(molecule, atomsToDraw)); } catch (Exception exc) { logger.debug("Caught an exception while logging in RingPlacer"); } atomPlacer.populatePolygonCorners(atomsToDraw, ringCenter, startAngle, addAngle, radius); }