Skip to content

Commit c7f3dc1

Browse files
committed
Move donut generation to a separate class, this will allow us to move charges too.
1 parent 627114b commit c7f3dc1

File tree

3 files changed

+143
-66
lines changed

3 files changed

+143
-66
lines changed

display/renderbasic/src/main/java/org/openscience/cdk/renderer/generators/standard/StandardBondGenerator.java

Lines changed: 27 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@
9393
*/
9494
final class StandardBondGenerator {
9595

96-
private final IAtomContainer container;
97-
private final AtomSymbol[] symbols;
98-
private final RendererModel parameters;
96+
private final IAtomContainer container;
97+
private final AtomSymbol[] symbols;
98+
private final RendererModel parameters;
99+
private final StandardDonutGenerator donutGenerator;
99100

100101
// logging
101102
private final ILoggingTool logger = LoggingToolFactory.createLoggingTool(getClass());
102103

103104
// indexes of atoms and rings
104105
private final Map<IAtom, Integer> atomIndexMap = new HashMap<IAtom, Integer>();
105106
private final Map<IBond, IAtomContainer> ringMap;
106-
private final Set<IBond> donuts = new HashSet<>();
107107

108108
// parameters
109109
private final double scale;
@@ -116,7 +116,6 @@ final class StandardBondGenerator {
116116
private final Color foreground, annotationColor;
117117
private final boolean fancyBoldWedges, fancyHashedWedges;
118118
private final double annotationDistance, annotationScale;
119-
private final boolean delocalisedDonuts;
120119
private final Font font;
121120
private final ElementGroup annotations;
122121
private final boolean forceDelocalised;
@@ -131,12 +130,18 @@ final class StandardBondGenerator {
131130
* @param parameters rendering options
132131
* @param stroke scaled stroke width
133132
*/
134-
private StandardBondGenerator(IAtomContainer container, AtomSymbol[] symbols, RendererModel parameters,
135-
ElementGroup annotations, Font font, double stroke) {
133+
private StandardBondGenerator(IAtomContainer container,
134+
AtomSymbol[] symbols,
135+
RendererModel parameters,
136+
ElementGroup annotations,
137+
Font font,
138+
double stroke,
139+
StandardDonutGenerator donutGen) {
136140
this.container = container;
137141
this.symbols = symbols;
138142
this.parameters = parameters;
139143
this.annotations = annotations;
144+
this.donutGenerator = donutGen;
140145

141146
// index atoms and rings
142147
for (int i = 0; i < container.getAtomCount(); i++)
@@ -159,7 +164,6 @@ private StandardBondGenerator(IAtomContainer container, AtomSymbol[] symbols, Re
159164
this.annotationScale = (1 / scale) * parameters.get(StandardGenerator.AnnotationFontScale.class);
160165
this.annotationColor = parameters.get(StandardGenerator.AnnotationColor.class);
161166
this.forceDelocalised = parameters.get(StandardGenerator.ForceDelocalisedBondDisplay.class);
162-
this.delocalisedDonuts = parameters.get(StandardGenerator.DelocalisedDonutsBondDisplay.class);
163167
this.font = font;
164168

165169
// foreground is based on the carbon color
@@ -177,20 +181,18 @@ private StandardBondGenerator(IAtomContainer container, AtomSymbol[] symbols, Re
177181
* @param parameters rendering options
178182
* @param stroke scaled stroke width
179183
*/
180-
static IRenderingElement[] generateBonds(IAtomContainer container, AtomSymbol[] symbols, RendererModel parameters,
181-
double stroke, Font font, ElementGroup annotations) {
182-
StandardBondGenerator bondGenerator = new StandardBondGenerator(container, symbols, parameters, annotations,
183-
font, stroke);
184-
IRenderingElement[] elements;
185-
186-
IRenderingElement donuts = bondGenerator.generateDonuts();
187-
if (donuts != null) {
188-
elements = new IRenderingElement[container.getBondCount()+1];
189-
elements[elements.length-1] = donuts;
190-
} else {
191-
elements = new IRenderingElement[container.getBondCount()];
192-
}
193-
184+
static IRenderingElement[] generateBonds(IAtomContainer container,
185+
AtomSymbol[] symbols,
186+
RendererModel parameters,
187+
double stroke,
188+
Font font,
189+
ElementGroup annotations,
190+
StandardDonutGenerator donutGen) {
191+
StandardBondGenerator bondGenerator;
192+
bondGenerator = new StandardBondGenerator(container, symbols,
193+
parameters, annotations,
194+
font, stroke, donutGen);
195+
IRenderingElement[] elements = new IRenderingElement[container.getBondCount()];
194196
for (int i = 0; i < container.getBondCount(); i++) {
195197
final IBond bond = container.getBond(i);
196198
if (!StandardGenerator.isHidden(bond)) {
@@ -200,40 +202,6 @@ static IRenderingElement[] generateBonds(IAtomContainer container, AtomSymbol[]
200202
return elements;
201203
}
202204

203-
boolean canDelocalise(final IAtomContainer ring) {
204-
boolean okay = ring.getBondCount() <= 8;
205-
if (!okay)
206-
return false;
207-
for (IBond bond : ring.bonds()) {
208-
if (!bond.isAromatic())
209-
okay = false;
210-
if ((bond.getOrder() != null &&
211-
bond.getOrder() != UNSET) &&
212-
!forceDelocalised)
213-
okay = false;
214-
}
215-
return okay;
216-
}
217-
218-
IRenderingElement generateDonuts() {
219-
if (!delocalisedDonuts)
220-
return null;
221-
ElementGroup group = new ElementGroup();
222-
Set<IAtomContainer> rings = new HashSet<>(ringMap.values());
223-
for (IAtomContainer ring : rings) {
224-
if (!canDelocalise(ring))
225-
continue;
226-
for (IBond bond : ring.bonds())
227-
donuts.add(bond);
228-
Point2d p2 = GeometryUtil.get2DCenter(ring);
229-
double s = GeometryUtil.getBondLengthMedian(ring);
230-
double n = ring.getBondCount();
231-
double r = s / (2*Math.tan(Math.PI/n));
232-
group.add(new OvalElement(p2.x, p2.y, r-separation, false, foreground));
233-
}
234-
return group;
235-
}
236-
237205
/**
238206
* Generate a rendering element for a given bond.
239207
*
@@ -254,7 +222,7 @@ IRenderingElement generate(IBond bond) {
254222
case SINGLE:
255223
// TODO check small ring!
256224
if (bond.isAromatic()) {
257-
if (donuts.contains(bond))
225+
if (donutGenerator.isDelocalised(bond))
258226
elem = generateSingleBond(bond, atom1, atom2);
259227
else if (forceDelocalised)
260228
elem = generateDoubleBond(bond, forceDelocalised);
@@ -265,7 +233,7 @@ else if (forceDelocalised)
265233
break;
266234
case DOUBLE:
267235
if (bond.isAromatic()) {
268-
if (donuts.contains(bond))
236+
if (donutGenerator.isDelocalised(bond))
269237
elem = generateSingleBond(bond, atom1, atom2);
270238
else
271239
elem = generateDoubleBond(bond, forceDelocalised);
@@ -277,7 +245,7 @@ else if (forceDelocalised)
277245
break;
278246
default:
279247
if (bond.isAromatic() && order == UNSET) {
280-
if (donuts.contains(bond))
248+
if (donutGenerator.isDelocalised(bond))
281249
elem = generateSingleBond(bond, atom1, atom2);
282250
else
283251
elem = generateDoubleBond(bond, true);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (C) 2019 The Chemistry Development Kit (CDK) project
3+
*
4+
* Contact: cdk-devel@lists.sourceforge.net
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation; either version 2.1 of the License, or (at
9+
* your option) any later version. All we ask is that proper credit is given
10+
* for our work, which includes - but is not limited to - adding the above
11+
* copyright notice to the beginning of your source code files, and to any
12+
* copyright notice that you may distribute with programs based on this work.
13+
*
14+
* This program is distributed in the hope that it will be useful, but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17+
* License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public License
20+
* along with this program; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22+
*/
23+
24+
package org.openscience.cdk.renderer.generators.standard;
25+
26+
import org.openscience.cdk.geometry.GeometryUtil;
27+
import org.openscience.cdk.graph.Cycles;
28+
import org.openscience.cdk.interfaces.IAtom;
29+
import org.openscience.cdk.interfaces.IAtomContainer;
30+
import org.openscience.cdk.interfaces.IBond;
31+
import org.openscience.cdk.interfaces.IChemObject;
32+
import org.openscience.cdk.interfaces.IRingSet;
33+
import org.openscience.cdk.renderer.RendererModel;
34+
import org.openscience.cdk.renderer.elements.ElementGroup;
35+
import org.openscience.cdk.renderer.elements.IRenderingElement;
36+
import org.openscience.cdk.renderer.elements.OvalElement;
37+
import org.openscience.cdk.renderer.generators.standard.StandardGenerator.DelocalisedDonutsBondDisplay;
38+
import org.openscience.cdk.renderer.generators.standard.StandardGenerator.ForceDelocalisedBondDisplay;
39+
40+
import javax.vecmath.Point2d;
41+
import java.awt.Color;
42+
import java.util.HashSet;
43+
import java.util.Set;
44+
45+
import static org.openscience.cdk.interfaces.IBond.Order.UNSET;
46+
47+
final class StandardDonutGenerator {
48+
49+
// bonds involved in donuts!
50+
private final Set<IBond> bonds = new HashSet<>();
51+
private final boolean forceDelocalised;
52+
private final boolean delocalisedDonuts;
53+
private final double dbSpacing;
54+
private final Color fgColor;
55+
private final IAtomContainer mol;
56+
57+
public StandardDonutGenerator(IAtomContainer mol, RendererModel model) {
58+
this.forceDelocalised = model.get(ForceDelocalisedBondDisplay.class);
59+
this.delocalisedDonuts = model.get(DelocalisedDonutsBondDisplay.class);
60+
this.dbSpacing = model.get(StandardGenerator.BondSeparation.class);
61+
this.fgColor = model.get(StandardGenerator.AtomColor.class).getAtomColor(
62+
mol.getBuilder().newInstance(IAtom.class, "C"));
63+
this.mol = mol;
64+
}
65+
66+
private boolean canDelocalise(final IAtomContainer ring) {
67+
boolean okay = ring.getBondCount() <= 8;
68+
if (!okay)
69+
return false;
70+
for (IBond bond : ring.bonds()) {
71+
if (!bond.isAromatic())
72+
okay = false;
73+
if ((bond.getOrder() != null &&
74+
bond.getOrder() != UNSET) &&
75+
!forceDelocalised)
76+
okay = false;
77+
}
78+
return okay;
79+
}
80+
81+
IRenderingElement generate() {
82+
if (!delocalisedDonuts)
83+
return null;
84+
ElementGroup group = new ElementGroup();
85+
IRingSet rset = Cycles.edgeShort(mol).toRingSet();
86+
for (IAtomContainer ring : rset.atomContainers()) {
87+
if (!canDelocalise(ring))
88+
continue;
89+
for (IBond bond : ring.bonds()) {
90+
bonds.add(bond);
91+
}
92+
Point2d p2 = GeometryUtil.get2DCenter(ring);
93+
double s = GeometryUtil.getBondLengthMedian(ring);
94+
double n = ring.getBondCount();
95+
double r = s / (2 * Math.tan(Math.PI / n));
96+
group.add(new OvalElement(p2.x, p2.y, r - dbSpacing,
97+
false, fgColor));
98+
}
99+
return group;
100+
}
101+
102+
boolean isDelocalised(IBond bond) {
103+
return bonds.contains(bond);
104+
}
105+
}

display/renderbasic/src/main/java/org/openscience/cdk/renderer/generators/standard/StandardGenerator.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,15 @@ public IRenderingElement generate(IAtomContainer container, RendererModel parame
211211

212212
ElementGroup annotations = new ElementGroup();
213213

214+
StandardDonutGenerator donutGenerator = new StandardDonutGenerator(container, parameters);
215+
IRenderingElement donuts = donutGenerator.generate();
216+
214217
AtomSymbol[] symbols = generateAtomSymbols(container, symbolRemap, visibility, parameters, annotations, foreground, stroke);
215-
IRenderingElement[] bondElements = StandardBondGenerator.generateBonds(container, symbols, parameters, stroke,
216-
font, annotations);
218+
IRenderingElement[] bondElements;
219+
bondElements = StandardBondGenerator.generateBonds(container, symbols,
220+
parameters, stroke,
221+
font, annotations,
222+
donutGenerator);
217223

218224
final HighlightStyle style = parameters.get(Highlighting.class);
219225
final double glowWidth = parameters.get(OuterGlowWidth.class);
@@ -241,10 +247,8 @@ public IRenderingElement generate(IAtomContainer container, RendererModel parame
241247
}
242248
}
243249

244-
// donuts for delocalised aromatic
245-
if (bondElements.length > container.getBondCount()) {
246-
frontLayer.add(bondElements[bondElements.length - 1]);
247-
}
250+
// bonds for delocalised aromatic
251+
frontLayer.add(donuts);
248252

249253
// convert the atom symbols to IRenderingElements
250254
for (int i = 0; i < container.getAtomCount(); i++) {
@@ -1156,7 +1160,7 @@ public Boolean getDefault() {
11561160
}
11571161

11581162
/**
1159-
* Render small delocalised rings as donuts/life buoys? This can sometimes
1163+
* Render small delocalised rings as bonds/life buoys? This can sometimes
11601164
* be misleading for fused rings but is commonly used.
11611165
*/
11621166
public static final class DelocalisedDonutsBondDisplay extends AbstractGeneratorParameter<Boolean> {

0 commit comments

Comments
 (0)