5656import javax .vecmath .Vector2d ;
5757import java .awt .Color ;
5858import java .awt .Font ;
59- import java .awt .Shape ;
6059import java .util .ArrayList ;
6160import java .util .Arrays ;
6261import java .util .Collections ;
@@ -104,6 +103,7 @@ final class StandardBondGenerator {
104103 // indexes of atoms and rings
105104 private final Map <IAtom , Integer > atomIndexMap = new HashMap <IAtom , Integer >();
106105 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,7 @@ 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 aromaticDonuts = true ;
119+ private final boolean delocalisedDonuts ;
120120 private final Font font ;
121121 private final ElementGroup annotations ;
122122 private final boolean forceDelocalised ;
@@ -159,6 +159,7 @@ private StandardBondGenerator(IAtomContainer container, AtomSymbol[] symbols, Re
159159 this .annotationScale = (1 / scale ) * parameters .get (StandardGenerator .AnnotationFontScale .class );
160160 this .annotationColor = parameters .get (StandardGenerator .AnnotationColor .class );
161161 this .forceDelocalised = parameters .get (StandardGenerator .ForceDelocalisedBondDisplay .class );
162+ this .delocalisedDonuts = parameters .get (StandardGenerator .DelocalisedDonutsBondDisplay .class );
162163 this .font = font ;
163164
164165 // foreground is based on the carbon color
@@ -180,40 +181,55 @@ static IRenderingElement[] generateBonds(IAtomContainer container, AtomSymbol[]
180181 double stroke , Font font , ElementGroup annotations ) {
181182 StandardBondGenerator bondGenerator = new StandardBondGenerator (container , symbols , parameters , annotations ,
182183 font , stroke );
183- IRenderingElement [] elements = new IRenderingElement [container .getBondCount ()];
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+
184194 for (int i = 0 ; i < container .getBondCount (); i ++) {
185195 final IBond bond = container .getBond (i );
186196 if (!StandardGenerator .isHidden (bond )) {
187197 elements [i ] = bondGenerator .generate (bond );
188198 }
189199 }
190- if (bondGenerator .aromaticDonuts ) {
191- IRenderingElement donuts = bondGenerator .generateDonuts ();
192- if (donuts != null ) {
193- elements = Arrays .copyOf (elements , elements .length + 1 );
194- elements [elements .length -1 ] = donuts ;
195- }
196- }
197200 return elements ;
198201 }
199202
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+
200218 IRenderingElement generateDonuts () {
219+ if (!delocalisedDonuts )
220+ return null ;
201221 ElementGroup group = new ElementGroup ();
202222 Set <IAtomContainer > rings = new HashSet <>(ringMap .values ());
203223 for (IAtomContainer ring : rings ) {
204- if (ring .getBondCount () <= 8 ) {
205- Point2d p2 = GeometryUtil .get2DCenter (ring );
206- if (ring .getBondCount () == 5 ) {
207- TextOutline to = new TextOutline ("–" , font ).resize (1 /scale , -1 /scale );
208- to = to .translate (p2 .x -to .getCenter ().getX (),
209- p2 .y -to .getCenter ().getY ());
210- // group.add(GeneralPath.shapeOf(to.getOutline(), foreground));
211- }
212- double s = GeometryUtil .getBondLengthMedian (ring );
213- double n = ring .getBondCount ();
214- double r = s / (2 *Math .tan (Math .PI /n ));
215- // group.add(new OvalElement(p2.x, p2.y, r-separation, false, foreground));
216- }
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 ));
217233 }
218234 return group ;
219235 }
@@ -238,16 +254,18 @@ IRenderingElement generate(IBond bond) {
238254 case SINGLE :
239255 // TODO check small ring!
240256 if (bond .isAromatic ()) {
241- if (forceDelocalised && !aromaticDonuts ) {
242- elem = generateDoubleBond (bond , true );
243- } else
257+ if (donuts .contains (bond ))
258+ elem = generateSingleBond (bond , atom1 , atom2 );
259+ else if (forceDelocalised )
260+ elem = generateDoubleBond (bond , forceDelocalised );
261+ else
244262 elem = generateSingleBond (bond , atom1 , atom2 );
245263 } else
246264 elem = generateSingleBond (bond , atom1 , atom2 );
247265 break ;
248266 case DOUBLE :
249267 if (bond .isAromatic ()) {
250- if (forceDelocalised && aromaticDonuts )
268+ if (donuts . contains ( bond ) )
251269 elem = generateSingleBond (bond , atom1 , atom2 );
252270 else
253271 elem = generateDoubleBond (bond , forceDelocalised );
@@ -259,7 +277,10 @@ IRenderingElement generate(IBond bond) {
259277 break ;
260278 default :
261279 if (bond .isAromatic () && order == UNSET ) {
262- elem = generateDoubleBond (bond , true );
280+ if (donuts .contains (bond ))
281+ elem = generateSingleBond (bond , atom1 , atom2 );
282+ else
283+ elem = generateDoubleBond (bond , true );
263284 } else {
264285 // bond orders > 3 not supported
265286 elem = generateDashedBond (atom1 , atom2 );
@@ -700,17 +721,17 @@ private IRenderingElement generateDoubleBond(IBond bond, boolean arom) {
700721 }
701722 } else if (!(hasDisplayedSymbol (atom1 ) && hasDisplayedSymbol (atom2 ))) {
702723 if (atom1Bonds .size () == 1 && atom2Bonds .isEmpty ())
703- return generateOffsetDoubleBond (bond , atom1 , atom2 , atom1Bonds .get (0 ), atom2Bonds , dashed );
724+ return generateOffsetDoubleBond (bond , atom1 , atom2 , atom1Bonds .get (0 ), atom2Bonds , arom );
704725 else if (atom2Bonds .size () == 1 && atom1Bonds .isEmpty ())
705- return generateOffsetDoubleBond (bond , atom2 , atom1 , atom2Bonds .get (0 ), atom1Bonds , dashed );
726+ return generateOffsetDoubleBond (bond , atom2 , atom1 , atom2Bonds .get (0 ), atom1Bonds , arom );
706727 else if (specialOffsetBondNextToWedge (atom1 , atom1Bonds ))
707- return generateOffsetDoubleBond (bond , atom1 , atom2 , selectPlainSingleBond (atom1Bonds ), atom2Bonds , dashed );
728+ return generateOffsetDoubleBond (bond , atom1 , atom2 , selectPlainSingleBond (atom1Bonds ), atom2Bonds , arom );
708729 else if (specialOffsetBondNextToWedge (atom2 , atom2Bonds ))
709- return generateOffsetDoubleBond (bond , atom2 , atom1 , selectPlainSingleBond (atom2Bonds ), atom1Bonds , dashed );
730+ return generateOffsetDoubleBond (bond , atom2 , atom1 , selectPlainSingleBond (atom2Bonds ), atom1Bonds , arom );
710731 else if (atom1Bonds .size () == 1 )
711- return generateOffsetDoubleBond (bond , atom1 , atom2 , atom1Bonds .get (0 ), atom2Bonds , dashed );
732+ return generateOffsetDoubleBond (bond , atom1 , atom2 , atom1Bonds .get (0 ), atom2Bonds , arom );
712733 else if (atom2Bonds .size () == 1 )
713- return generateOffsetDoubleBond (bond , atom2 , atom1 , atom2Bonds .get (0 ), atom1Bonds , dashed );
734+ return generateOffsetDoubleBond (bond , atom2 , atom1 , atom2Bonds .get (0 ), atom1Bonds , arom );
714735 else
715736 return generateCenteredDoubleBond (bond , atom1 , atom2 , atom1Bonds , atom2Bonds );
716737 } else {
0 commit comments