View Javadoc

1   package org.molwind.chemical.view;
2   
3   /*
4    * This file is part of Molwind.
5    *
6    * Molwind is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Molwind is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Molwind. If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  import java.awt.Color;
21  import java.awt.Dimension;
22  import java.awt.Font;
23  import java.awt.Graphics2D;
24  import java.awt.image.BufferedImage;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  import org.openscience.cdk.DefaultChemObjectBuilder;
31  import org.openscience.cdk.aromaticity.HueckelAromaticityDetector;
32  import org.openscience.cdk.exception.CDKException;
33  import org.openscience.cdk.geometry.GeometryTools;
34  import org.openscience.cdk.interfaces.IAtomContainer;
35  import org.openscience.cdk.interfaces.IBond;
36  import org.openscience.cdk.interfaces.IMolecule;
37  import org.openscience.cdk.interfaces.IMoleculeSet;
38  import org.openscience.cdk.isomorphism.UniversalIsomorphismTester;
39  import org.openscience.cdk.isomorphism.mcss.RMap;
40  import org.openscience.cdk.renderer.IRenderer2D;
41  import org.openscience.cdk.renderer.Renderer2D;
42  import org.openscience.cdk.renderer.Renderer2DModel;
43  
44  import org.molwind.chemical.model.ChemicalEntity;
45  import org.molwind.model.PartOf;
46  
47  /**
48   * SubstructureRenderer implements a strategy to render molecules with parent
49   * substructures to be highlighted.
50   *
51   * @author <a href="mailto:oliver.karch@molwind.org">Oliver Karch</a>
52   * @version 1.0
53   */
54  public class SubstructureRenderer implements MoleculeRenderer {
55  
56      private double zoom = 1d;
57  
58      /**
59       * Get the Zoom value.
60       *
61       * @return
62       *      the Zoom value
63       */
64      public double getZoom() {
65          return zoom;
66      }
67  
68      /**
69       * Set the Zoom value.
70       *
71       * @param newZoom
72       *      the new Zoom value
73       */
74      public void setZoom(final double newZoom) {
75          this.zoom = newZoom;
76      }
77  
78  
79      private void detectAromaticity(final ChemicalEntity chemicalEntity)
80      throws CDKException {
81          IMolecule molecule = chemicalEntity.getMolecule();
82          HueckelAromaticityDetector.detectAromaticity(molecule);
83      }
84  
85      private IAtomContainer markSubstructure(
86              final ChemicalEntity chemicalEntity,
87              final ChemicalEntity[] parents)
88      throws CDKException {
89          IMolecule molecule = chemicalEntity.getMolecule();
90          ArrayList atomIndex = new ArrayList();
91  
92          for (int i = 0; i < parents.length; i++) {
93              IMolecule parentMolecule = parents[i].getMolecule();
94              if (UniversalIsomorphismTester.isSubgraph(
95                      molecule, parentMolecule)) {
96                  List sMap = UniversalIsomorphismTester.getSubgraphAtomsMaps(
97                          molecule, parentMolecule);
98                  Iterator it = ((List) sMap.get(0)).iterator();
99  
100                 while (it.hasNext()) {
101                     RMap rm = (RMap) it.next();
102                     Integer ai = Integer.valueOf(rm.getId1());
103                     if (!atomIndex.contains(ai)) {
104                         atomIndex.add(ai);
105                     }
106                 }
107             }
108         }
109 
110         Integer[] ato = new Integer[atomIndex.size()];
111         ato = (Integer[]) atomIndex.toArray(ato);
112         IAtomContainer highB =
113             DefaultChemObjectBuilder.getInstance().newAtomContainer();
114         IBond bond;
115 
116         for (int i = 0; i < ato.length; i++) {
117             for (int j = i + 1; j < ato.length; j++) {
118                 bond = highB.getBond(molecule.getAtom(ato[i]),
119                         molecule.getAtom(ato[j]));
120                 if (bond != null) {
121                     highB.addBond(bond);
122                 }
123             }
124         }
125         return highB;
126     }
127 
128     private Color getBackgroundColor(final ChemicalEntity chemicalEntity) {
129         ChemicalEntity[] children =
130             (ChemicalEntity[]) chemicalEntity.getRelationship(
131                     PartOf.right(chemicalEntity));
132 
133         Color background = Color.white;
134 
135         if (children.length > 0) {
136             if (children.length < 6) {
137                 background = new Color(190, 255, 190);
138             } else if (children.length < 16) {
139                 background = new Color(255, 255, 160);
140             } else {
141                 background = new Color(255, 160, 160);
142             }
143         }
144         return background;
145     }
146 
147     private Dimension scaleMolecule(final ChemicalEntity chemicalEntity,
148             final HashMap coordinates) {
149         IMolecule molecule = chemicalEntity.getMolecule();
150         Dimension imageDimension = GeometryTools.get2DDimension(
151                 molecule, coordinates);
152 
153         GeometryTools.makeRenderingCoordinates(
154                 (IMoleculeSet) molecule, coordinates);
155         GeometryTools.scaleMolecule(molecule, imageDimension, 15, coordinates);
156         GeometryTools.center(molecule, imageDimension, coordinates);
157         GeometryTools.translateAllPositive(molecule, coordinates);
158         GeometryTools.translate2D(molecule, 10, 0, coordinates);
159 
160         double[] minMax = GeometryTools.getMinMax(molecule, coordinates);
161         int width = (int) minMax[2] - (int) minMax[0];
162         int height = (int) minMax[3] - (int) minMax[1];
163         imageDimension.setSize(width + 10, height + 10);
164 
165         return imageDimension;
166     }
167 
168     private BufferedImage createImage(final Dimension dimension) {
169         return new BufferedImage(((int) dimension.getWidth()) + 15,
170                 ((int) dimension.getHeight()) + 15, BufferedImage.TYPE_INT_RGB);
171     }
172 
173     private BufferedImage renderImage(
174             final Dimension dimension,
175             final ChemicalEntity chemicalEntity,
176             final IAtomContainer highB,
177             final HashMap coordinates) {
178         BufferedImage image = createImage(dimension);
179         Renderer2DModel r2dm = new Renderer2DModel();
180 
181         r2dm.setSelectedPartColor(Color.GREEN);
182         r2dm.setSelectedPart(highB);
183 
184         double z = getZoom() * 2;
185         int width = (int) (dimension.getWidth() * z);
186         int height = (int) (dimension.getHeight() * z);
187 
188         Font font = new Font("Arial", Font.PLAIN, (int) (12 * 2 * z));
189 
190         r2dm.setBackgroundDimension(dimension);
191         r2dm.setDrawNumbers(false);
192         r2dm.setColorAtomsByType(true);
193         r2dm.setShowAromaticity(false);
194         r2dm.setZoomFactor(z);
195         r2dm.setUseAntiAliasing(true);
196         r2dm.setIsCompact(false);
197 
198         Color background = getBackgroundColor(chemicalEntity);
199         r2dm.setBackColor(background);
200 
201         Graphics2D g2d = image.createGraphics();
202         IRenderer2D r2d = new Renderer2D(r2dm);
203 
204         g2d.setColor(background);
205         g2d.fillRect(0, 0, width + 15, height + 15);
206         g2d.setColor(Color.black);
207 
208         r2dm.setRenderingCoordinates(coordinates);
209         IMolecule molecule = chemicalEntity.getMolecule();
210         r2d.paintMoleculeSet((IMoleculeSet) molecule, g2d);
211 
212         return image;
213     }
214 
215 
216     /**
217      * Returns a graphical representation of a molecule.
218      *
219      * @param chemicalEntity
220      *      the chemical entity
221      * @return
222      *      a buffered image depicting the molecule
223      * @throws org.openscience.cdk.exception.CDKException
224      *      is thrown upon CDK error
225      */
226     public BufferedImage getImage(final ChemicalEntity chemicalEntity)
227     throws CDKException {
228         ChemicalEntity[] parents =
229             (ChemicalEntity[]) chemicalEntity.getRelationship(
230                     PartOf.left(chemicalEntity));
231 
232         for (int i = 0; i < parents.length; i++) {
233             detectAromaticity(parents[i]);
234         }
235         detectAromaticity(chemicalEntity);
236 
237         IAtomContainer hiMol = markSubstructure(chemicalEntity, parents);
238         HashMap coordinates = new HashMap();
239         Dimension dimension = scaleMolecule(chemicalEntity, coordinates);
240         BufferedImage image = renderImage(dimension, chemicalEntity,
241                 hiMol, coordinates);
242 
243         return image;
244     }
245 
246 }