3232import org .openscience .cdk .interfaces .IRingSet ;
3333import org .openscience .cdk .renderer .RendererModel ;
3434import org .openscience .cdk .renderer .elements .ElementGroup ;
35+ import org .openscience .cdk .renderer .elements .GeneralPath ;
3536import org .openscience .cdk .renderer .elements .IRenderingElement ;
3637import org .openscience .cdk .renderer .elements .OvalElement ;
38+ import org .openscience .cdk .renderer .generators .BasicSceneGenerator ;
3739import org .openscience .cdk .renderer .generators .standard .StandardGenerator .DelocalisedDonutsBondDisplay ;
3840import org .openscience .cdk .renderer .generators .standard .StandardGenerator .ForceDelocalisedBondDisplay ;
3941
4042import javax .vecmath .Point2d ;
4143import java .awt .Color ;
44+ import java .awt .Font ;
4245import java .util .HashSet ;
4346import java .util .Set ;
4447
@@ -48,19 +51,25 @@ final class StandardDonutGenerator {
4851
4952 // bonds involved in donuts!
5053 private final Set <IBond > bonds = new HashSet <>();
54+ // atoms with delocalised charge
55+ private final Set <IAtom > atoms = new HashSet <>();
5156 private final boolean forceDelocalised ;
5257 private final boolean delocalisedDonuts ;
5358 private final double dbSpacing ;
59+ private final double scale ;
5460 private final Color fgColor ;
61+ private final Font font ;
5562 private final IAtomContainer mol ;
5663
57- public StandardDonutGenerator (IAtomContainer mol , RendererModel model ) {
64+ public StandardDonutGenerator (IAtomContainer mol , Font font , RendererModel model ) {
65+ this .mol = mol ;
66+ this .font = font ;
5867 this .forceDelocalised = model .get (ForceDelocalisedBondDisplay .class );
5968 this .delocalisedDonuts = model .get (DelocalisedDonutsBondDisplay .class );
6069 this .dbSpacing = model .get (StandardGenerator .BondSeparation .class );
70+ this .scale = model .get (BasicSceneGenerator .Scale .class );
6171 this .fgColor = model .get (StandardGenerator .AtomColor .class ).getAtomColor (
6272 mol .getBuilder ().newInstance (IAtom .class , "C" ));
63- this .mol = mol ;
6473 }
6574
6675 private boolean canDelocalise (final IAtomContainer ring ) {
@@ -89,11 +98,42 @@ IRenderingElement generate() {
8998 for (IBond bond : ring .bonds ()) {
9099 bonds .add (bond );
91100 }
101+ int charge = 0 ;
102+ int unpaired = 0 ;
103+ for (IAtom atom : ring .atoms ()) {
104+ Integer q = atom .getFormalCharge ();
105+ if (q == null || q == 0 ) {
106+ continue ;
107+ }
108+ int nCyclic = 0 ;
109+ for (IBond bond : mol .getConnectedBondsList (atom ))
110+ if (bond .isInRing ())
111+ nCyclic ++;
112+ if (nCyclic > 2 )
113+ continue ;
114+ atoms .add (atom );
115+ charge += atom .getFormalCharge ();
116+ }
92117 Point2d p2 = GeometryUtil .get2DCenter (ring );
118+
119+ if (charge != 0 ) {
120+ String qText = charge < 0 ? "–" : "+" ;
121+ if (charge < -1 )
122+ qText = Math .abs (charge ) + qText ;
123+ else if (charge > +1 )
124+ qText = Math .abs (charge ) + qText ;
125+
126+ TextOutline qSym = new TextOutline (qText , font );
127+ qSym = qSym .resize (1 / scale , -1 / scale );
128+ qSym = qSym .translate (p2 .x - qSym .getCenter ().getX (),
129+ p2 .y - qSym .getCenter ().getY ());
130+ group .add (GeneralPath .shapeOf (qSym .getOutline (), fgColor ));
131+ }
132+
93133 double s = GeometryUtil .getBondLengthMedian (ring );
94134 double n = ring .getBondCount ();
95135 double r = s / (2 * Math .tan (Math .PI / n ));
96- group .add (new OvalElement (p2 .x , p2 .y , r - dbSpacing ,
136+ group .add (new OvalElement (p2 .x , p2 .y , r - 1.5 * dbSpacing ,
97137 false , fgColor ));
98138 }
99139 return group ;
@@ -102,4 +142,8 @@ IRenderingElement generate() {
102142 boolean isDelocalised (IBond bond ) {
103143 return bonds .contains (bond );
104144 }
145+
146+ boolean isChargeDelocalised (IAtom atom ) {
147+ return atoms .contains (atom );
148+ }
105149}
0 commit comments