Skip to content

Commit

Permalink
Charges should be delocalised in the middle of the ring, e.g. cyclope…
Browse files Browse the repository at this point in the history
…ntadiene.
  • Loading branch information
johnmay committed Jul 28, 2019
1 parent c7f3dc1 commit 8c6dd38
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@
import org.openscience.cdk.interfaces.IRingSet;
import org.openscience.cdk.renderer.RendererModel;
import org.openscience.cdk.renderer.elements.ElementGroup;
import org.openscience.cdk.renderer.elements.GeneralPath;
import org.openscience.cdk.renderer.elements.IRenderingElement;
import org.openscience.cdk.renderer.elements.OvalElement;
import org.openscience.cdk.renderer.generators.BasicSceneGenerator;
import org.openscience.cdk.renderer.generators.standard.StandardGenerator.DelocalisedDonutsBondDisplay;
import org.openscience.cdk.renderer.generators.standard.StandardGenerator.ForceDelocalisedBondDisplay;

import javax.vecmath.Point2d;
import java.awt.Color;
import java.awt.Font;
import java.util.HashSet;
import java.util.Set;

Expand All @@ -48,19 +51,25 @@ final class StandardDonutGenerator {

// bonds involved in donuts!
private final Set<IBond> bonds = new HashSet<>();
// atoms with delocalised charge
private final Set<IAtom> atoms = new HashSet<>();
private final boolean forceDelocalised;
private final boolean delocalisedDonuts;
private final double dbSpacing;
private final double scale;
private final Color fgColor;
private final Font font;
private final IAtomContainer mol;

public StandardDonutGenerator(IAtomContainer mol, RendererModel model) {
public StandardDonutGenerator(IAtomContainer mol, Font font, RendererModel model) {
this.mol = mol;
this.font = font;
this.forceDelocalised = model.get(ForceDelocalisedBondDisplay.class);
this.delocalisedDonuts = model.get(DelocalisedDonutsBondDisplay.class);
this.dbSpacing = model.get(StandardGenerator.BondSeparation.class);
this.scale = model.get(BasicSceneGenerator.Scale.class);
this.fgColor = model.get(StandardGenerator.AtomColor.class).getAtomColor(
mol.getBuilder().newInstance(IAtom.class, "C"));
this.mol = mol;
}

private boolean canDelocalise(final IAtomContainer ring) {
Expand Down Expand Up @@ -89,11 +98,42 @@ IRenderingElement generate() {
for (IBond bond : ring.bonds()) {
bonds.add(bond);
}
int charge = 0;
int unpaired = 0;
for (IAtom atom : ring.atoms()) {
Integer q = atom.getFormalCharge();
if (q == null || q == 0) {
continue;
}
int nCyclic = 0;
for (IBond bond : mol.getConnectedBondsList(atom))
if (bond.isInRing())
nCyclic++;
if (nCyclic > 2)
continue;
atoms.add(atom);
charge += atom.getFormalCharge();
}
Point2d p2 = GeometryUtil.get2DCenter(ring);

if (charge != 0) {
String qText = charge < 0 ? "–" : "+";
if (charge < -1)
qText = Math.abs(charge) + qText;
else if (charge > +1)
qText = Math.abs(charge) + qText;

TextOutline qSym = new TextOutline(qText, font);
qSym = qSym.resize(1 / scale, -1 / scale);
qSym = qSym.translate(p2.x - qSym.getCenter().getX(),
p2.y - qSym.getCenter().getY());
group.add(GeneralPath.shapeOf(qSym.getOutline(), fgColor));
}

double s = GeometryUtil.getBondLengthMedian(ring);
double n = ring.getBondCount();
double r = s / (2 * Math.tan(Math.PI / n));
group.add(new OvalElement(p2.x, p2.y, r - dbSpacing,
group.add(new OvalElement(p2.x, p2.y, r - 1.5*dbSpacing,
false, fgColor));
}
return group;
Expand All @@ -102,4 +142,8 @@ IRenderingElement generate() {
boolean isDelocalised(IBond bond) {
return bonds.contains(bond);
}

boolean isChargeDelocalised(IAtom atom) {
return atoms.contains(atom);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,14 @@ public IRenderingElement generate(IAtomContainer container, RendererModel parame

ElementGroup annotations = new ElementGroup();

StandardDonutGenerator donutGenerator = new StandardDonutGenerator(container, parameters);
StandardDonutGenerator donutGenerator;
donutGenerator = new StandardDonutGenerator(container, font, parameters);
IRenderingElement donuts = donutGenerator.generate();

AtomSymbol[] symbols = generateAtomSymbols(container, symbolRemap, visibility, parameters, annotations, foreground, stroke);
AtomSymbol[] symbols = generateAtomSymbols(container, symbolRemap,
visibility, parameters,
annotations, foreground,
stroke, donutGenerator);
IRenderingElement[] bondElements;
bondElements = StandardBondGenerator.generateBonds(container, symbols,
parameters, stroke,
Expand Down Expand Up @@ -367,7 +371,8 @@ private AtomSymbol[] generateAtomSymbols(IAtomContainer container,
RendererModel parameters,
ElementGroup annotations,
Color foreground,
double stroke) {
double stroke,
StandardDonutGenerator donutGen) {

final double scale = parameters.get(BasicSceneGenerator.Scale.class);
final double annDist = parameters.get(AnnotationDistance.class)
Expand Down Expand Up @@ -424,9 +429,16 @@ private AtomSymbol[] generateAtomSymbols(IAtomContainer container,

if (remapped) {
symbols[i] = atomGenerator.generateAbbreviatedSymbol(symbolRemap.get(atom), hPosition);
} else {
} else if (donutGen.isChargeDelocalised(atom)) {
Integer charge = atom.getFormalCharge();
atom.setFormalCharge(0);
// can't think of a better way to handle this without API
// change to symbol visibility
if (atom.getAtomicNumber() != 6)
symbols[i] = atomGenerator.generateSymbol(container, atom, hPosition, parameters);
atom.setFormalCharge(charge);
} else
symbols[i] = atomGenerator.generateSymbol(container, atom, hPosition, parameters);
}

if (symbols[i] != null) {

Expand Down

0 comments on commit 8c6dd38

Please sign in to comment.