📄 atomplacer.java
字号:
/* $RCSfile$ * $Author: egonw $ * $Date: 2007-08-28 11:23:21 +0200 (Tue, 28 Aug 2007) $ * $Revision: 8737 $ * * Copyright (C) 2003-2007 The Chemistry Development Kit (CDK) project * * 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.Comparator;import java.util.HashMap;import java.util.Vector;import javax.vecmath.Point2d;import javax.vecmath.Vector2d;import org.openscience.cdk.CDKConstants;import org.openscience.cdk.geometry.BondTools;import org.openscience.cdk.geometry.GeometryTools;import org.openscience.cdk.geometry.GeometryToolsInternalCoordinates;import org.openscience.cdk.graph.PathTools;import org.openscience.cdk.graph.matrix.ConnectionMatrix;import org.openscience.cdk.interfaces.IAtom;import org.openscience.cdk.interfaces.IAtomContainer;import org.openscience.cdk.interfaces.IBond;import org.openscience.cdk.interfaces.IMolecule;//removed during debugging. Before you put this in again, contact// er@doktor-steinbeck.de//import org.openscience.cdk.tools.HydrogenAdder;import org.openscience.cdk.tools.LoggingTool;import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;/** * Methods for generating coordinates for atoms in various situations. They can * be used for Automated Structure Diagram Generation or in the interactive * buildup of molecules by the user. * *@author steinbeck *@cdk.created 2003-08-29 *@cdk.module sdg */public class AtomPlacer{ public final static boolean debug = true; private static LoggingTool logger = new LoggingTool(AtomPlacer.class); /** * The molecule to be laid out. To be assigned from outside */ IAtomContainer molecule = null; final Comparator ATOM_ORDER = new Comparator() { public int compare(Object o1, Object o2) { IAtom a1 = (IAtom) o1; IAtom a2 = (IAtom) o2; int i1 = ((Integer) a1.getProperty("Weight")).intValue(); int i2 = ((Integer) a2.getProperty("Weight")).intValue(); if (i1 < i2) { return -1; } if (i1 == i2) { return 0; } return 1; } }; /** * Constructor for the AtomPlacer object */ public AtomPlacer() { } /** * Return the molecule the AtomPlacer currently works with * *@return the molecule the AtomPlacer currently works with */ public IAtomContainer getMolecule() { return this.molecule; } /** * Sets the molecule the AtomPlacer currently works with * *@param molecule the molecule the AtomPlacer currently works with */ public void setMolecule(IAtomContainer molecule) { this.molecule = molecule; } /** * Distribute the bonded atoms (neighbours) of an atom such that they fill the * remaining space around an atom in a geometrically nice way. * IMPORTANT: This method is not supposed to handle the * case of one or no place neighbor. In the case of * one placed neigbor, the chain placement methods * should be used. * *@param atom The atom whose partners are to be placed *@param placedNeighbours The atoms which are already placed *@param unplacedNeighbours The partners to be placed *@param bondLength The standared bond length for the newly placed * Atoms *@param sharedAtomsCenter The 2D centre of the placed Atoms */ public void distributePartners(IAtom atom, IAtomContainer placedNeighbours, Point2d sharedAtomsCenter, IAtomContainer unplacedNeighbours, double bondLength) { distributePartners(atom, placedNeighbours, sharedAtomsCenter, unplacedNeighbours, bondLength, null); } /** * Distribute the bonded atoms (neighbours) of an atom such that they fill the * remaining space around an atom in a geometrically nice way. * IMPORTANT: This method is not supposed to handle the * case of one or no place neighbor. In the case of * one placed neigbor, the chain placement methods * should be used. * *@param atom The atom whose partners are to be placed *@param placedNeighbours The atoms which are already placed *@param unplacedNeighbours The partners to be placed *@param bondLength The standared bond length for the newly placed * Atoms *@param sharedAtomsCenter The 2D centre of the placed Atoms */ public void distributePartners(IAtom atom, IAtomContainer placedNeighbours, Point2d sharedAtomsCenter, IAtomContainer unplacedNeighbours, double bondLength, HashMap renderingCoordinates) { double occupiedAngle = 0; //double smallestDistance = Double.MAX_VALUE; //IAtom[] nearestAtoms = new IAtom[2]; IAtom[] sortedAtoms = null; double startAngle = 0.0; double addAngle = 0.0; double radius = 0.0; double remainingAngle = 0.0; /* * calculate the direction away from the already placed partners of atom */ //Point2d sharedAtomsCenter = sharedAtoms.get2DCenter(); Vector2d sharedAtomsCenterVector = new Vector2d(sharedAtomsCenter); Vector2d newDirection = new Vector2d(atom.getPoint2d()); if(renderingCoordinates!=null && renderingCoordinates.get(atom)!=null) newDirection = new Vector2d((Point2d)renderingCoordinates.get(atom)); Vector2d occupiedDirection = new Vector2d(sharedAtomsCenter); occupiedDirection.sub(newDirection); logger.debug("distributePartners->occupiedDirection.lenght(): " + occupiedDirection.length()); Vector atomsToDraw = new Vector(); logger.debug("Number of shared atoms: ", placedNeighbours.getAtomCount()); /* * IMPORTANT: This method is not supposed to handle the * case of one or no place neighbor. In the case of * one placed neigbor, the chain placement methods * should be used. */ if (placedNeighbours.getAtomCount() == 1) { logger.debug("Only one neighbour..."); for (int f = 0; f < unplacedNeighbours.getAtomCount(); f++) { atomsToDraw.addElement(unplacedNeighbours.getAtom(f)); } addAngle = Math.PI * 2 / (unplacedNeighbours.getAtomCount() + placedNeighbours.getAtomCount()); /* * IMPORTANT: At this point we need a calculation of the * start angle. * Not done yet. */ IAtom placedAtom = placedNeighbours.getAtom(0);// double xDiff = atom.getX2d() - placedAtom.getX2d();// double yDiff = atom.getY2d() - placedAtom.getY2d(); double xDiff = placedAtom.getPoint2d().x - atom.getPoint2d().x; double yDiff = placedAtom.getPoint2d().y - atom.getPoint2d().y; if(renderingCoordinates!=null){ if(renderingCoordinates.get(atom)==null) renderingCoordinates.put(atom,atom.getPoint2d()); xDiff = ((Point2d)renderingCoordinates.get(placedAtom)).x - ((Point2d)renderingCoordinates.get(atom)).x; yDiff = ((Point2d)renderingCoordinates.get(placedAtom)).y - ((Point2d)renderingCoordinates.get(atom)).y; } logger.debug("distributePartners->xdiff: " + Math.toDegrees(xDiff)); logger.debug("distributePartners->ydiff: " + Math.toDegrees(yDiff)); startAngle = GeometryToolsInternalCoordinates.getAngle(xDiff, yDiff); //- (Math.PI / 2.0); logger.debug("distributePartners->angle: " + Math.toDegrees(startAngle)); populatePolygonCorners(atomsToDraw, new Point2d(renderingCoordinates==null ? atom.getPoint2d() : ((Point2d)renderingCoordinates.get(atom))), startAngle, addAngle, bondLength,renderingCoordinates); return; } else if (placedNeighbours.getAtomCount() == 0) { logger.debug("First atom..."); for (int f = 0; f < unplacedNeighbours.getAtomCount(); f++) { atomsToDraw.addElement(unplacedNeighbours.getAtom(f)); } addAngle = Math.PI * 2.0 / unplacedNeighbours.getAtomCount(); /* * IMPORTANT: At this point we need a calculation of the * start angle. Not done yet. */ startAngle = 0.0; populatePolygonCorners(atomsToDraw, new Point2d(renderingCoordinates==null ? atom.getPoint2d() : ((Point2d)renderingCoordinates.get(atom))), startAngle, addAngle, bondLength,renderingCoordinates); return; } /* * if the least hindered side of the atom is clearly defined (bondLength / 10 is an arbitrary value that seemed reasonable) */ //newDirection.sub(sharedAtomsCenterVector); sharedAtomsCenterVector.sub(newDirection); newDirection = sharedAtomsCenterVector; newDirection.normalize(); newDirection.scale(bondLength); newDirection.negate(); logger.debug("distributePartners->newDirection.lenght(): " + newDirection.length()); Point2d distanceMeasure = new Point2d(atom.getPoint2d()); distanceMeasure.add(newDirection); /* * get the two sharedAtom partners with the smallest distance to the new center */ sortedAtoms = AtomContainerManipulator.getAtomArray(placedNeighbours); if(renderingCoordinates!=null) GeometryTools.sortBy2DDistance(sortedAtoms, distanceMeasure,renderingCoordinates); else GeometryToolsInternalCoordinates.sortBy2DDistance(sortedAtoms, distanceMeasure); Vector2d closestPoint1 = new Vector2d(sortedAtoms[0].getPoint2d()); Vector2d closestPoint2 = new Vector2d(sortedAtoms[1].getPoint2d()); closestPoint1.sub(new Vector2d(atom.getPoint2d())); closestPoint2.sub(new Vector2d(atom.getPoint2d())); if(renderingCoordinates!=null){ GeometryTools.sortBy2DDistance(sortedAtoms, distanceMeasure, renderingCoordinates); closestPoint1 = new Vector2d(((Point2d)renderingCoordinates.get(sortedAtoms[0]))); closestPoint2 = new Vector2d(((Point2d)renderingCoordinates.get(sortedAtoms[1]))); closestPoint1.sub(new Vector2d(((Point2d)renderingCoordinates.get(atom)))); closestPoint2.sub(new Vector2d(((Point2d)renderingCoordinates.get(atom)))); } occupiedAngle = closestPoint1.angle(occupiedDirection); occupiedAngle += closestPoint2.angle(occupiedDirection); double angle1 = GeometryTools.getAngle(sortedAtoms[0].getPoint2d().x - atom.getPoint2d().x, sortedAtoms[0].getPoint2d().y - atom.getPoint2d().y); double angle2 = GeometryTools.getAngle(sortedAtoms[1].getPoint2d().x - atom.getPoint2d().x, sortedAtoms[1].getPoint2d().y - atom.getPoint2d().y); double angle3 = GeometryTools.getAngle(distanceMeasure.x - atom.getPoint2d().x, distanceMeasure.y - atom.getPoint2d().y); if(renderingCoordinates!=null){ angle1 = GeometryTools.getAngle(((Point2d)renderingCoordinates.get(sortedAtoms[0])).x - ((Point2d)renderingCoordinates.get(atom)).x, ((Point2d)renderingCoordinates.get(sortedAtoms[0])).y - ((Point2d)renderingCoordinates.get(atom)).y); angle2 = GeometryTools.getAngle(((Point2d)renderingCoordinates.get(sortedAtoms[1])).x - ((Point2d)renderingCoordinates.get(atom)).x, ((Point2d)renderingCoordinates.get(sortedAtoms[1])).y - ((Point2d)renderingCoordinates.get(atom)).y); angle3 = GeometryTools.getAngle(distanceMeasure.x - ((Point2d)renderingCoordinates.get(atom)).x, distanceMeasure.y - ((Point2d)renderingCoordinates.get(atom)).y); } if (debug) { try { logger.debug("distributePartners->sortedAtoms[0]: ", (molecule.getAtomNumber(sortedAtoms[0]) + 1)); logger.debug("distributePartners->sortedAtoms[1]: ", (molecule.getAtomNumber(sortedAtoms[1]) + 1)); logger.debug("distributePartners->angle1: ", Math.toDegrees(angle1)); logger.debug("distributePartners->angle2: ", Math.toDegrees(angle2)); } catch (Exception exc) { logger.debug(exc); } } IAtom startAtom = null; if (angle1 > angle3) { if (angle1 - angle3 < Math.PI) { startAtom = sortedAtoms[1]; } else { // 12 o'clock is between the two vectors startAtom = sortedAtoms[0]; } } else { if (angle3 - angle1 < Math.PI) { startAtom = sortedAtoms[0]; } else { // 12 o'clock is between the two vectors startAtom = sortedAtoms[1]; } } remainingAngle = (2 * Math.PI) - occupiedAngle; addAngle = remainingAngle / (unplacedNeighbours.getAtomCount() + 1); if (debug) { try { logger.debug("distributePartners->startAtom: " + (molecule.getAtomNumber(startAtom) + 1)); logger.debug("distributePartners->remainingAngle: " + Math.toDegrees(remainingAngle)); logger.debug("distributePartners->addAngle: " + Math.toDegrees(addAngle)); logger.debug("distributePartners-> partners.getAtomCount(): " + unplacedNeighbours.getAtomCount()); } catch (Exception exc) { logger.debug(exc); } } for (int f = 0; f < unplacedNeighbours.getAtomCount(); f++) { atomsToDraw.addElement(unplacedNeighbours.getAtom(f)); } radius = bondLength; startAngle = GeometryTools.getAngle(startAtom.getPoint2d().x - atom.getPoint2d().x, startAtom.getPoint2d().y - atom.getPoint2d().y); if(renderingCoordinates!=null){ startAngle = GeometryTools.getAngle(((Point2d)renderingCoordinates.get(startAtom)).x - ((Point2d)renderingCoordinates.get(atom)).x, ((Point2d)renderingCoordinates.get(startAtom)).y - ((Point2d)renderingCoordinates.get(atom)).y); } logger.debug("Before check: distributePartners->startAngle: " + startAngle);// if (startAngle < (Math.PI + 0.001) && startAngle > (Math.PI// -0.001))// {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -