📄 structurediagramgenerator.java
字号:
/* $Revision: 9065 $ $Author: egonw $ $Date: 2007-10-14 22:04:57 +0200 (Sun, 14 Oct 2007) $ * * Copyright (C) 1997-2007 Christoph Steinbeck <steinbeck@users.sf.net> * * Contact: cdk-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * All we ask is that proper credit is given for our work, which includes * - but is not limited to - adding the above copyright notice to the beginning * of your source code files, and to any copyright notice that you may distribute * with programs based on this work. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * */package org.openscience.cdk.layout;import java.util.Iterator;import java.util.List;import javax.vecmath.Point2d;import javax.vecmath.Vector2d;import org.openscience.cdk.CDKConstants;import org.openscience.cdk.exception.CDKException;import org.openscience.cdk.geometry.GeometryToolsInternalCoordinates;import org.openscience.cdk.graph.ConnectivityChecker;import org.openscience.cdk.interfaces.IAtom;import org.openscience.cdk.interfaces.IAtomContainer;import org.openscience.cdk.interfaces.IAtomContainerSet;import org.openscience.cdk.interfaces.IBond;import org.openscience.cdk.interfaces.IMolecule;import org.openscience.cdk.interfaces.IRing;import org.openscience.cdk.interfaces.IRingSet;import org.openscience.cdk.ringsearch.RingPartitioner;import org.openscience.cdk.ringsearch.SSSRFinder;import org.openscience.cdk.tools.LoggingTool;import org.openscience.cdk.tools.manipulator.AtomContainerSetManipulator;import org.openscience.cdk.tools.manipulator.RingSetManipulator;/** * Generates 2D coordinates for a molecule for which only connectivity is known * or the coordinates have been discarded for some reason. Usage: Create an * instance of this class, thereby assigning a molecule, call * generateCoordinates() and get your molecule back: * <pre> * StructureDiagramGenerator sdg = new StructureDiagramGenerator(); * sdg.setMolecule(someMolecule); * sdg.generateCoordinates(); * Molecule layedOutMol = sdg.getMolecule(); * </pre> * * <p>The method will fail if the molecule is disconnected. The * partitionIntoMolecules(AtomContainer) can help here. * * @author steinbeck * @cdk.created 2004-02-02 * @see org.openscience.cdk.graph.ConnectivityChecker#partitionIntoMolecules(IAtomContainer) * @cdk.keyword Layout * @cdk.keyword Structure Diagram Generation (SDG) * @cdk.keyword 2D coordinates * @cdk.keyword Coordinate generation, 2D * @cdk.dictref blue-obelisk:layoutMolecule * @cdk.module sdg * @cdk.bug 1610997 * @cdk.bug 1536561 */public class StructureDiagramGenerator{ private LoggingTool logger = new LoggingTool(StructureDiagramGenerator.class); private static TemplateHandler DEFAULT_TEMPLATE_HANDLER = null; private IMolecule molecule; private IRingSet sssr; private double bondLength = 1.5; private Vector2d firstBondVector; private RingPlacer ringPlacer = new RingPlacer(); private AtomPlacer atomPlacer = new AtomPlacer(); private List ringSystems = null; private final String disconnectedMessage = "Molecule not connected. Use ConnectivityChecker.partitionIntoMolecules() and do the layout for every single component."; private TemplateHandler templateHandler = null; private boolean useTemplates = true; /** Atoms of the molecule that mapped a template */ private IAtomContainerSet mappedSubstructures; /** * The empty constructor. */ public StructureDiagramGenerator() { } /** * Creates an instance of this class while assigning a molecule to be layed * out. * * @param molecule The molecule to be layed out. */ public StructureDiagramGenerator(IMolecule molecule) { this(); setMolecule(molecule, false); templateHandler = new TemplateHandler(molecule.getBuilder()); } /** * Assings a molecule to be layed out. Call generateCoordinates() to do the * actual layout. * * @param mol the molecule for which coordinates are to be generated. * @param clone Should the whole process be performed with a cloned copy? */ public void setMolecule(IMolecule mol, boolean clone) { templateHandler = new TemplateHandler(mol.getBuilder()); IAtom atom = null; if (clone) { try { this.molecule = (IMolecule) mol.clone(); } catch (CloneNotSupportedException e) { logger.error("Should clone, but exception occured: ", e.getMessage()); logger.debug(e); } } else { this.molecule = mol; } for (int f = 0; f < molecule.getAtomCount(); f++) { atom = molecule.getAtom(f); atom.setPoint2d(null); atom.setFlag(CDKConstants.ISPLACED, false); atom.setFlag(CDKConstants.VISITED, false); atom.setFlag(CDKConstants.ISINRING, false); atom.setFlag(CDKConstants.ISALIPHATIC, false); } atomPlacer.setMolecule(this.molecule); ringPlacer.setMolecule(this.molecule); ringPlacer.setAtomPlacer(this.atomPlacer); } /** * Sets whether to use templates or not. Some complicated ring systems * like adamantane are only nicely layouted when using templates. This * option is by default set true. * *@param useTemplates set true to use templates, false otherwise */ public void setUseTemplates(boolean useTemplates) { this.useTemplates = useTemplates; } /** * Returns whether the use of templates is enabled or disabled. * * @return true, when the use of templates is enables, false otherwise */ public boolean getUseTemplates() { return useTemplates; } /** * Sets the templateHandler attribute of the StructureDiagramGenerator object * * @param templateHandler The new templateHandler value */ public void setTemplateHandler(TemplateHandler templateHandler) { this.templateHandler = templateHandler; } /** * Gets the templateHandler attribute of the StructureDiagramGenerator object * * @return The templateHandler value */ public TemplateHandler getTemplateHandler() { if (templateHandler == null) { return DEFAULT_TEMPLATE_HANDLER; } else { return templateHandler; } } /** * Assings a molecule to be layed out. Call generateCoordinates() to do the * actual layout. * * @param molecule the molecule for which coordinates are to be generated. */ public void setMolecule(IMolecule molecule) { setMolecule(molecule, true); } /** * Returns the molecule, usually used after a call of generateCoordinates() * * @return The molecule with new coordinates (if generateCoordinates() had * been called) */ public IMolecule getMolecule() { return molecule; } /** * This method uses generateCoordinates, but it removes the hydrogens first, * lays out the structuren and then adds them again. * * @throws java.lang.Exception if an error occurs * @see #generateCoordinates */ public void generateExperimentalCoordinates() throws java.lang.Exception { generateExperimentalCoordinates(new Vector2d(0, 1)); } /** * Generates 2D coordinates on the non-hydrogen skeleton, after which * coordinates for the hydrogens are calculated. * * @param firstBondVector the vector of the first bond to lay out * @throws java.lang.Exception if an error occurs */ public void generateExperimentalCoordinates(Vector2d firstBondVector) throws java.lang.Exception { // first make a shallow copy: Atom/Bond references are kept IMolecule original = molecule; IMolecule shallowCopy = molecule.getBuilder().newMolecule(molecule); // ok, delete H's from //IAtom[] atoms = shallowCopy.getAtoms(); for (int i = 0; i < shallowCopy.getAtomCount(); i++) { IAtom curAtom = shallowCopy.getAtom(i); if (curAtom.getSymbol().equals("H")) { shallowCopy.removeAtomAndConnectedElectronContainers(curAtom); curAtom.setPoint2d(null); } } // do layout on the shallow copy molecule = shallowCopy; generateCoordinates(firstBondVector); double bondLength = GeometryToolsInternalCoordinates.getBondLengthAverage(molecule); // ok, now create the coordinates for the hydrogens HydrogenPlacer hPlacer = new HydrogenPlacer(); molecule = original; hPlacer.placeHydrogens2D(molecule, bondLength); } /** * The main method of this StructurDiagramGenerator. Assign a molecule to the * StructurDiagramGenerator, call the generateCoordinates() method and get * your molecule back. * * @param firstBondVector The vector of the first bond to lay out * @throws java.lang.Exception if an error occurs */ public void generateCoordinates(Vector2d firstBondVector) throws java.lang.Exception { int safetyCounter = 0; /* * if molecule contains only one Atom, don't fail, simply * set coordinates to simplest: 0,0. See bug #780545 */ logger.debug("Entry point of generateCoordinates()"); logger.debug("We have a molecules with " + molecule.getAtomCount() + " atoms."); if (molecule.getAtomCount() == 1) { molecule.getAtom(0).setPoint2d(new Point2d(0, 0)); return; } if (!ConnectivityChecker.isConnected(molecule)) { logger.debug("Molecule is not connected. Throwing exception."); throw new CDKException(disconnectedMessage); } else { logger.debug("Molecule is connected."); } /* * compute the minimum number of rings as * given by Frerejacque, Bull. Soc. Chim. Fr., 5, 1008 (1939) */ int nrOfEdges = molecule.getBondCount(); //Vector2d ringSystemVector = null; //Vector2d newRingSystemVector = null; this.firstBondVector = firstBondVector; boolean templateMapped = false; double angle; /* * First we check if we can map any templates with predefined coordinates * Those are stored as MDL molfiles in data/templates */ if (useTemplates && (System.getProperty("java.version").indexOf("1.3.") == -1)) { logger.debug("Initializing TemplateHandler"); logger.debug("TemplateHander initialized"); logger.debug("Now starting Template Detection in Molecule..."); mappedSubstructures = getTemplateHandler().getMappedSubstructures(molecule); templateMapped = mappedSubstructures.getAtomContainerCount() > 0; logger.debug("Template Detection finished"); logger.debug("Number of found templates: " + mappedSubstructures.getAtomContainerCount()); } int expectedRingCount = nrOfEdges - molecule.getAtomCount() + 1; if (expectedRingCount > 0) { logger.debug("*** Start of handling rings. ***"); /* * Get the smallest set of smallest rings on this molecule */ SSSRFinder sssrf = new SSSRFinder(molecule); sssr = sssrf.findSSSR(); if (sssr.getAtomContainerCount() < 1) { return; } /* * Order the rings because SSSRFinder.findSSSR() returns rings in an * undeterministic order. */ AtomContainerSetManipulator.sort(sssr); /* * Mark all the atoms from the ring system as "ISINRING" */ markRingAtoms(sssr); /* * Give a handle of our molecule to the ringPlacer */ ringPlacer.setMolecule(molecule); ringPlacer.checkAndMarkPlaced(sssr); /* * Partition the smallest set of smallest rings into disconnected ring system. * The RingPartioner returns a Vector containing RingSets. Each of the RingSets contains * rings that are connected to each other either as bridged ringsystems, fused rings or * via spiro connections.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -