📄 abstractrenderer2d.java
字号:
/* $Revision: 8742 $ $Author: egonw $ $Date: 2007-08-28 11:46:31 +0200 (Tue, 28 Aug 2007) $ * * Copyright (C) 2005-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.renderer;import java.awt.BasicStroke;import java.awt.Color;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics2D;import java.awt.Point;import java.awt.RenderingHints;import java.awt.event.MouseEvent;import java.awt.event.MouseMotionListener;import java.util.ArrayList;import java.util.Iterator;import java.util.Vector;import javax.vecmath.Point2d;import javax.vecmath.Vector2d;import org.openscience.cdk.CDKConstants;import org.openscience.cdk.config.AtomTypeFactory;import org.openscience.cdk.config.IsotopeFactory;import org.openscience.cdk.geometry.GeometryTools;import org.openscience.cdk.geometry.GeometryToolsInternalCoordinates;import org.openscience.cdk.interfaces.IAtom;import org.openscience.cdk.interfaces.IAtomContainer;import org.openscience.cdk.interfaces.IBond;import org.openscience.cdk.interfaces.IChemObject;import org.openscience.cdk.interfaces.IIsotope;import org.openscience.cdk.interfaces.IPseudoAtom;import org.openscience.cdk.interfaces.IRing;import org.openscience.cdk.interfaces.IRingSet;import org.openscience.cdk.tools.LoggingTool;import org.openscience.cdk.tools.manipulator.RingSetManipulator;import org.openscience.cdk.validate.ProblemMarker;/** * A Renderer class which draws 2D representations of molecules onto a given * graphics objects using information from a Renderer2DModel. * * <p>This renderer uses two coordinate systems. One that is a world coordinates * system which is generated from the document coordinates. Additionally, the * screen coordinates make up the second system, and are calculated by applying * a zoom factor to the world coordinates. * * <p>The coordinate system used for display has its origin in the left-bottom * corner, with the x axis to the right, and the y axis towards the top of the * screen. The system is thus right handed. * * <p>The two main methods are paintMolecule() and paintChemModel(). Others might * not show full rendering, e.g. anti-aliasing. * * <p>This modules tries to adhere to guidelines being developed by the IUPAC * which results can be found at <a href="http://www.angelfire.com/sc3/iupacstructures/"> * http://www.angelfire.com/sc3/iupacstructures/</a> . * * @author steinbeck * @author egonw * @cdk.module render * @cdk.created 2002-10-03 * @cdk.keyword viewer, 2D-viewer * * @see org.openscience.cdk.renderer.Renderer2DModel */abstract class AbstractRenderer2D implements MouseMotionListener{ final static BasicStroke stroke = new BasicStroke(1.0f); protected LoggingTool logger; boolean debug = true; IsotopeFactory isotopeFactory; int[] tooltiparea = null; protected Renderer2DModel r2dm; int graphicsHeight; public boolean useScreenSize=true; /** * Constructs a Renderer2D with a default settings model. */ AbstractRenderer2D() { this(new Renderer2DModel()); } /** * Constructs a Renderer2D. * *@param r2dm The settings model to use for rendering. */ AbstractRenderer2D(Renderer2DModel r2dm) { this.r2dm = r2dm; logger = new LoggingTool(this); } protected void setupIsotopeFactory(IChemObject object) { if (isotopeFactory == null) { try { isotopeFactory = IsotopeFactory.getInstance(object.getBuilder()); } catch (Exception exception) { logger.error("Error while instantiating IsotopeFactory"); logger.warn("Will not be able to display undefault isotopes"); logger.debug(exception); } } } protected void customizeRendering(Graphics2D graphics) { if (r2dm.getUseAntiAliasing()) { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } graphics.setStroke(stroke); } /** *@param minmax array of length for with min and max 2D coordinates */ public void paintBoundingBox(double[] minmax, String caption, int side, Graphics2D graphics) { int[] ints = new int[4]; ints[0] = (int) minmax[0] - side; // min x ints[1] = (int) minmax[1] - side; // min y ints[2] = (int) minmax[2] + side; // max x ints[3] = (int) minmax[3] + side; // max y int[] screenCoords = getScreenCoordinates(ints); int heigth = screenCoords[1] - screenCoords[3]; int width = screenCoords[2] - screenCoords[0]; graphics.drawRect((int) screenCoords[0], (int) screenCoords[3], width, heigth); // draw reaction ID Font unscaledFont = r2dm.getFont(); if (unscaledFont == null) { unscaledFont = graphics.getFont(); } float fontSize = getScreenSize(unscaledFont.getSize()); graphics.setFont(unscaledFont.deriveFont(fontSize)); graphics.drawString(caption, (int) screenCoords[0], (int) screenCoords[3]); graphics.setFont(unscaledFont); } public void paintLassoLines(Graphics2D graphics) { Vector points = r2dm.getLassoPoints(); if (points.size() > 1) { Point point1 = (Point) points.elementAt(0); Point point2; for (int i = 1; i < points.size(); i++) { point2 = (Point) points.elementAt(i); graphics.drawLine(point1.x, point1.y, point2.x, point2.y); point1 = point2; } } } /** * Searches through all the atoms in the given array of atoms, triggers the * paintColouredAtoms method if the atom has got a certain color and triggers * the paintAtomSymbol method if the symbol of the atom is not C. */ public void paintAtoms(IAtomContainer atomCon, Graphics2D graphics) { for (int i = 0; i < atomCon.getAtomCount(); i++) { paintAtom(atomCon, atomCon.getAtom(i), graphics); } } public void paintAtom(IAtomContainer container, IAtom atom, Graphics2D graphics) { if (!r2dm.getShowExplicitHydrogens() && atom.getSymbol().equals("H")) return; logger.debug("Painting atom "); Color atomBackColor = r2dm.getAtomBackgroundColor(atom); if (atom.equals(r2dm.getHighlightedAtom())) { paintColouredAtomBackground(atom, r2dm.getHoverOverColor(), graphics); } if((r2dm.getSelectedPart()!=null && (r2dm.getSelectedPart().contains(r2dm.getHighlightedAtom()) || r2dm.getSelectedPart().contains(r2dm.getHighlightedBond())) && r2dm.getSelectedPart().contains(atom)) || (r2dm.getSelectedPart()!=null && r2dm.getSelectedPart().getAtomCount()==1 && r2dm.getSelectedPart().getAtom(0)==atom)){ paintColouredAtomBackground(atom, r2dm.getSelectedPartColor(), graphics); } if(r2dm.getExternalSelectedPart()!=null && r2dm.getExternalSelectedPart().contains(atom)){ paintColouredAtomBackground(atom, r2dm.getExternalHighlightColor(), graphics); atomBackColor=r2dm.getExternalHighlightColor(); } if(r2dm.getMerge().get(atom)!=null || r2dm.getMerge().values().contains(atom)){ paintColouredAtomBackground(atom, r2dm.getHoverOverColor(),graphics); } int alignment = GeometryTools.getBestAlignmentForLabel(container, atom, r2dm.getRenderingCoordinates()); boolean drawSymbol = false; boolean isRadical = (container.getConnectedSingleElectronsCount(atom) > 0); if (atom instanceof IPseudoAtom) { drawSymbol = false;// if (atom instanceof FragmentAtom) {// paintFragmentAtom((FragmentAtom)atom, atomBackColor, graphics,// alignment, isRadical);// } else { paintPseudoAtomLabel((IPseudoAtom) atom, atomBackColor, graphics, alignment, isRadical);// } return; } else if (!atom.getSymbol().equals("C")) { /* * only show element for non-carbon atoms, * unless (see below)... */ drawSymbol = true; } else if (r2dm.getKekuleStructure()) { // ... unless carbon must be drawn because in Kekule mode drawSymbol = true; } else if (atom.getFormalCharge() != 0) { // ... unless carbon is charged drawSymbol = true; } else if (container.getConnectedBondsList(atom).size() < 1) { // ... unless carbon is unbonded drawSymbol = true; } else if (r2dm.getShowEndCarbons() && (container.getConnectedBondsList(atom).size() == 1)) { drawSymbol = true; } else if (atom.getProperty(ProblemMarker.ERROR_MARKER) != null) { // ... unless carbon is unbonded drawSymbol = true; } else if (atom.getMassNumber() != 0) { try { if (atom.getMassNumber() != IsotopeFactory.getInstance(container.getBuilder()). getMajorIsotope(atom.getSymbol()).getMassNumber()) { drawSymbol = true; } } catch (Exception exception) { logger.debug("Could not get an instance of IsotopeFactory"); } } if (r2dm.drawNumbers() && !drawSymbol && !r2dm.getIsCompact()) { paintNumberOnly(atom, atomBackColor, graphics, atom.getProperty("OriginalNumber")!=null ? ((Integer)atom.getProperty("OriginalNumber")).intValue()+1 : container.getAtomNumber(atom) + 1); } if (drawSymbol || isRadical) { paintAtomSymbol(atom, atomBackColor, graphics, alignment, atom.getProperty("OriginalNumber")!=null ? ((Integer)atom.getProperty("OriginalNumber")).intValue()+1 : container.getAtomNumber(atom) + 1, isRadical); } if (r2dm.getShowTooltip() && (atom == r2dm.getHighlightedAtom() ||( r2dm.getExternalSelectedPart()!=null && r2dm.getExternalSelectedPart().contains(atom))) && r2dm.getToolTipText(atom) != null) { paintToolTip(atom, graphics, container.getAtomNumber(atom) + 1); } } /** * Paints a rectangle of the given color at the position of the given atom. * For example when the atom is highlighted. * *@param atom The atom to be drawn *@param color The color of the atom to be drawn */ public void paintColouredAtomBackground(org.openscience.cdk.interfaces.IAtom atom, Color color, Graphics2D graphics) { if(r2dm.getRenderingCoordinate(atom)==null) return; int atomRadius = r2dm.getAtomRadius(); graphics.setColor(color); int[] coords = {(int) r2dm.getRenderingCoordinate(atom).x - (atomRadius / 2), (int) r2dm.getRenderingCoordinate(atom).y + (atomRadius / 2)}; int radius = (int) getScreenSize(atomRadius); coords = getScreenCoordinates(coords); if(r2dm.getIsCompact()) graphics.drawRect(coords[0], coords[1], radius, radius); else graphics.fillRect(coords[0], coords[1], radius, radius); } /** * Paints the given atom symbol. It first outputs some empty space using the * background color, slightly larger than the space that the symbol occupies. * The atom symbol is then printed into the empty space. <p> * * The algorithm uses four steps: * <ol> * <li> it calculates the widths and heights of all label parts * <li> it calculates the x's and y's of all label parts * <li> it creates empty backgrounds for all label parts * <li> it draws all label parts * </ol> * * *@param atom The atom to be drawn *@param graphics Graphics2D to draw too *@param alignment How to align the H's *@param atomNumber Number of the atom in the AtomContainer, 0 is not in * container */ public void paintAtomSymbol(IAtom atom, Color backColor, Graphics2D graphics, int alignment, int atomNumber, boolean isRadical) { if (r2dm.getRenderingCoordinate(atom) == null) { logger.warn("Cannot draw atom without 2D coordinate"); return; } //This is for the compact version just with a square in the right color if (r2dm.getIsCompact()) { if (!atom.getSymbol().equals("C")) { int labelX = (int) (r2dm.getRenderingCoordinate(atom).x - 2); int labelY = (int) (r2dm.getRenderingCoordinate(atom).y + 2); try{ AtomTypeFactory factory = AtomTypeFactory.getInstance("org/openscience/cdk/config/jmol_atomtypes.txt",atom.getBuilder()); factory.configure(atom); }catch(Exception ex){ //We choose black if reading not possible logger.debug(ex); } Color atomColor = r2dm.getAtomColor(atom, Color.BLACK); paintEmptySpace(labelX, labelY, 5, 5, 0, atomColor, graphics); } return; } // The fonts for calculating geometries float subscriptFraction = 0.7f; Font normalFont = r2dm.getFont(); if (normalFont == null) { normalFont = graphics.getFont(); } int normalFontSize = normalFont.getSize(); Font subscriptFont = normalFont.deriveFont( normalFontSize * subscriptFraction); // get drawing fonts float normalScreenFontSize = getScreenSize(normalFontSize); Font normalScreenFont = normalFont.deriveFont(normalScreenFontSize); Font subscriptScreenFont = normalScreenFont.deriveFont( normalScreenFontSize * subscriptFraction); // STEP 1: calculate widths and heights for all parts in the label // calculate SYMBOL width, height String atomSymbol = atom.getSymbol(); if (r2dm.drawNumbers()) { if (atomNumber != 0 && !atomSymbol.equals("")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -