~ubuntu-branches/ubuntu/maverick/cdk/maverick

« back to all changes in this revision

Viewing changes to src/org/openscience/cdk/layout/StructureDiagramGenerator.java

  • Committer: Bazaar Package Importer
  • Author(s): Paul Cager
  • Date: 2008-04-09 21:17:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080409211753-46lmjw5z8mx5pd8d
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $Revision: 9065 $ $Author: egonw $ $Date: 2007-10-14 22:04:57 +0200 (Sun, 14 Oct 2007) $
 
2
 *
 
3
 *  Copyright (C) 1997-2007  Christoph Steinbeck <steinbeck@users.sf.net>
 
4
 *
 
5
 *  Contact: cdk-devel@lists.sourceforge.net
 
6
 *
 
7
 *  This program is free software; you can redistribute it and/or
 
8
 *  modify it under the terms of the GNU Lesser General Public License
 
9
 *  as published by the Free Software Foundation; either version 2.1
 
10
 *  of the License, or (at your option) any later version.
 
11
 *  All we ask is that proper credit is given for our work, which includes
 
12
 *  - but is not limited to - adding the above copyright notice to the beginning
 
13
 *  of your source code files, and to any copyright notice that you may distribute
 
14
 *  with programs based on this work.
 
15
 *
 
16
 *  This program is distributed in the hope that it will be useful,
 
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 *  GNU Lesser General Public License for more details.
 
20
 *
 
21
 *  You should have received a copy of the GNU Lesser General Public License
 
22
 *  along with this program; if not, write to the Free Software
 
23
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
24
 *
 
25
 */
 
26
package org.openscience.cdk.layout;
 
27
 
 
28
import java.util.Iterator;
 
29
import java.util.List;
 
30
 
 
31
import javax.vecmath.Point2d;
 
32
import javax.vecmath.Vector2d;
 
33
 
 
34
import org.openscience.cdk.CDKConstants;
 
35
import org.openscience.cdk.exception.CDKException;
 
36
import org.openscience.cdk.geometry.GeometryToolsInternalCoordinates;
 
37
import org.openscience.cdk.graph.ConnectivityChecker;
 
38
import org.openscience.cdk.interfaces.IAtom;
 
39
import org.openscience.cdk.interfaces.IAtomContainer;
 
40
import org.openscience.cdk.interfaces.IAtomContainerSet;
 
41
import org.openscience.cdk.interfaces.IBond;
 
42
import org.openscience.cdk.interfaces.IMolecule;
 
43
import org.openscience.cdk.interfaces.IRing;
 
44
import org.openscience.cdk.interfaces.IRingSet;
 
45
import org.openscience.cdk.ringsearch.RingPartitioner;
 
46
import org.openscience.cdk.ringsearch.SSSRFinder;
 
47
import org.openscience.cdk.tools.LoggingTool;
 
48
import org.openscience.cdk.tools.manipulator.AtomContainerSetManipulator;
 
49
import org.openscience.cdk.tools.manipulator.RingSetManipulator;
 
50
 
 
51
/**
 
52
 * Generates 2D coordinates for a molecule for which only connectivity is known
 
53
 * or the coordinates have been discarded for some reason. Usage: Create an
 
54
 * instance of this class, thereby assigning a molecule, call
 
55
 * generateCoordinates() and get your molecule back:
 
56
 * <pre>
 
57
 * StructureDiagramGenerator sdg = new StructureDiagramGenerator();
 
58
 * sdg.setMolecule(someMolecule);
 
59
 * sdg.generateCoordinates();
 
60
 * Molecule layedOutMol = sdg.getMolecule();
 
61
 * </pre>
 
62
 *
 
63
 * <p>The method will fail if the molecule is disconnected. The
 
64
 * partitionIntoMolecules(AtomContainer) can help here.
 
65
 *
 
66
 * @author      steinbeck
 
67
 * @cdk.created 2004-02-02
 
68
 * @see         org.openscience.cdk.graph.ConnectivityChecker#partitionIntoMolecules(IAtomContainer)
 
69
 * @cdk.keyword Layout
 
70
 * @cdk.keyword Structure Diagram Generation (SDG)
 
71
 * @cdk.keyword 2D coordinates
 
72
 * @cdk.keyword Coordinate generation, 2D
 
73
 * @cdk.dictref blue-obelisk:layoutMolecule
 
74
 * @cdk.module  sdg
 
75
 * @cdk.bug     1610997
 
76
 * @cdk.bug     1536561
 
77
 */
 
78
public class StructureDiagramGenerator
 
79
{
 
80
 
 
81
        private LoggingTool logger = new LoggingTool(StructureDiagramGenerator.class);
 
82
 
 
83
        private static TemplateHandler DEFAULT_TEMPLATE_HANDLER = null;
 
84
 
 
85
        private IMolecule molecule;
 
86
        private IRingSet sssr;
 
87
        private double bondLength = 1.5;
 
88
        private Vector2d firstBondVector;
 
89
        private RingPlacer ringPlacer = new RingPlacer();
 
90
        private AtomPlacer atomPlacer = new AtomPlacer();
 
91
        private List ringSystems = null;
 
92
        private final String disconnectedMessage = "Molecule not connected. Use ConnectivityChecker.partitionIntoMolecules() and do the layout for every single component.";
 
93
        private TemplateHandler templateHandler = null;
 
94
        private boolean useTemplates = true;
 
95
                                
 
96
        /** Atoms of the molecule that mapped a template */
 
97
        private IAtomContainerSet mappedSubstructures;
 
98
 
 
99
 
 
100
        /**
 
101
         *  The empty constructor.
 
102
         */
 
103
        public StructureDiagramGenerator()
 
104
        {
 
105
        }
 
106
 
 
107
 
 
108
        /**
 
109
         *  Creates an instance of this class while assigning a molecule to be layed
 
110
         *  out.
 
111
         *
 
112
         *  @param  molecule  The molecule to be layed out.
 
113
         */
 
114
        public StructureDiagramGenerator(IMolecule molecule) {
 
115
                this();
 
116
                setMolecule(molecule, false);
 
117
                templateHandler = new TemplateHandler(molecule.getBuilder());
 
118
        }
 
119
 
 
120
 
 
121
 
 
122
        /**
 
123
         *  Assings a molecule to be layed out. Call generateCoordinates() to do the
 
124
         *  actual layout.
 
125
         *
 
126
         *  @param  mol    the molecule for which coordinates are to be generated.
 
127
         *  @param  clone  Should the whole process be performed with a cloned copy?
 
128
         */
 
129
        public void setMolecule(IMolecule mol, boolean clone) {
 
130
                templateHandler = new TemplateHandler(mol.getBuilder());
 
131
                IAtom atom = null;
 
132
                if (clone)
 
133
                {
 
134
                        try {
 
135
                                this.molecule = (IMolecule) mol.clone();
 
136
                        } catch (CloneNotSupportedException e) {
 
137
                                logger.error("Should clone, but exception occured: ", e.getMessage());
 
138
                                logger.debug(e);
 
139
                        }
 
140
                } else
 
141
                {
 
142
                        this.molecule = mol;
 
143
                }
 
144
                for (int f = 0; f < molecule.getAtomCount(); f++)
 
145
                {
 
146
                        atom = molecule.getAtom(f);
 
147
                        atom.setPoint2d(null);
 
148
                        atom.setFlag(CDKConstants.ISPLACED, false);
 
149
                        atom.setFlag(CDKConstants.VISITED, false);
 
150
                        atom.setFlag(CDKConstants.ISINRING, false);
 
151
                        atom.setFlag(CDKConstants.ISALIPHATIC, false);
 
152
                }
 
153
                atomPlacer.setMolecule(this.molecule);
 
154
                ringPlacer.setMolecule(this.molecule);
 
155
                ringPlacer.setAtomPlacer(this.atomPlacer);
 
156
        }
 
157
 
 
158
 
 
159
        /**
 
160
         *  Sets whether to use templates or not. Some complicated ring systems
 
161
         *  like adamantane are only nicely layouted when using templates. This
 
162
         *  option is by default set true.
 
163
         *
 
164
         *@param  useTemplates  set true to use templates, false otherwise
 
165
         */
 
166
        public void setUseTemplates(boolean useTemplates)
 
167
        {
 
168
                this.useTemplates = useTemplates;
 
169
        }
 
170
 
 
171
 
 
172
        /**
 
173
         *  Returns whether the use of templates is enabled or disabled.
 
174
         *
 
175
         *  @return    true, when the use of templates is enables, false otherwise
 
176
         */
 
177
        public boolean getUseTemplates()
 
178
        {
 
179
                return useTemplates;
 
180
        }
 
181
 
 
182
 
 
183
        /**
 
184
         *  Sets the templateHandler attribute of the StructureDiagramGenerator object
 
185
         *
 
186
         *  @param  templateHandler  The new templateHandler value
 
187
         */
 
188
        public void setTemplateHandler(TemplateHandler templateHandler)
 
189
        {
 
190
                this.templateHandler = templateHandler;
 
191
        }
 
192
 
 
193
 
 
194
        /**
 
195
         *  Gets the templateHandler attribute of the StructureDiagramGenerator object
 
196
         *
 
197
         *  @return    The templateHandler value
 
198
         */
 
199
        public TemplateHandler getTemplateHandler()
 
200
        {
 
201
                if (templateHandler == null)
 
202
                {
 
203
                        return DEFAULT_TEMPLATE_HANDLER;
 
204
                }
 
205
                else
 
206
                {
 
207
                        return templateHandler;
 
208
                }  
 
209
        }
 
210
 
 
211
 
 
212
        /**
 
213
         *  Assings a molecule to be layed out. Call generateCoordinates() to do the
 
214
         *  actual layout.
 
215
         *
 
216
         *  @param  molecule  the molecule for which coordinates are to be generated.
 
217
         */
 
218
        public void setMolecule(IMolecule molecule)
 
219
        {
 
220
                setMolecule(molecule, true);
 
221
        }
 
222
 
 
223
 
 
224
        /**
 
225
         *  Returns the molecule, usually used after a call of generateCoordinates()
 
226
         *
 
227
         *  @return    The molecule with new coordinates (if generateCoordinates() had
 
228
         *             been called)
 
229
         */
 
230
        public IMolecule getMolecule()
 
231
        {
 
232
                return molecule;
 
233
        }
 
234
 
 
235
 
 
236
        /**
 
237
         *  This method uses generateCoordinates, but it removes the hydrogens first,
 
238
         *  lays out the structuren and then adds them again.
 
239
         *
 
240
         *  @throws  java.lang.Exception  if an error occurs
 
241
         *  @see     #generateCoordinates
 
242
         */
 
243
        public void generateExperimentalCoordinates() throws java.lang.Exception
 
244
        {
 
245
                generateExperimentalCoordinates(new Vector2d(0, 1));
 
246
        }
 
247
 
 
248
 
 
249
        /**
 
250
         * Generates 2D coordinates on the non-hydrogen skeleton, after which
 
251
         * coordinates for the hydrogens are calculated.
 
252
         * 
 
253
         * @param firstBondVector the vector of the first bond to lay out
 
254
         * @throws java.lang.Exception if an error occurs
 
255
         */
 
256
        public void generateExperimentalCoordinates(Vector2d firstBondVector) throws java.lang.Exception {
 
257
                // first make a shallow copy: Atom/Bond references are kept
 
258
                IMolecule original = molecule;
 
259
                IMolecule shallowCopy = molecule.getBuilder().newMolecule(molecule);
 
260
                // ok, delete H's from 
 
261
                //IAtom[] atoms = shallowCopy.getAtoms();
 
262
                for (int i = 0; i < shallowCopy.getAtomCount(); i++) {
 
263
                        IAtom curAtom = shallowCopy.getAtom(i);
 
264
                                if (curAtom.getSymbol().equals("H")) {
 
265
                                                shallowCopy.removeAtomAndConnectedElectronContainers(curAtom);
 
266
                                                curAtom.setPoint2d(null);
 
267
                                }
 
268
                }
 
269
                // do layout on the shallow copy
 
270
                molecule = shallowCopy;
 
271
                generateCoordinates(firstBondVector);
 
272
                double bondLength = GeometryToolsInternalCoordinates.getBondLengthAverage(molecule);
 
273
                // ok, now create the coordinates for the hydrogens
 
274
                HydrogenPlacer hPlacer = new HydrogenPlacer();
 
275
                molecule = original;
 
276
                hPlacer.placeHydrogens2D(molecule, bondLength);
 
277
        }
 
278
 
 
279
 
 
280
        /**
 
281
         *  The main method of this StructurDiagramGenerator. Assign a molecule to the
 
282
         *  StructurDiagramGenerator, call the generateCoordinates() method and get
 
283
         *  your molecule back.
 
284
         *
 
285
         *  @param  firstBondVector          The vector of the first bond to lay out
 
286
         *  @throws  java.lang.Exception     if an error occurs
 
287
         */
 
288
        public void generateCoordinates(Vector2d firstBondVector) throws java.lang.Exception
 
289
        {
 
290
                int safetyCounter = 0;
 
291
                /*
 
292
                 *  if molecule contains only one Atom, don't fail, simply
 
293
                 *  set coordinates to simplest: 0,0. See bug #780545
 
294
                 */
 
295
                logger.debug("Entry point of generateCoordinates()");
 
296
                logger.debug("We have a molecules with " + molecule.getAtomCount() + " atoms.");
 
297
                if (molecule.getAtomCount() == 1)
 
298
                {
 
299
                        molecule.getAtom(0).setPoint2d(new Point2d(0, 0));
 
300
                        return;
 
301
                }
 
302
                if (!ConnectivityChecker.isConnected(molecule))
 
303
                {
 
304
                        logger.debug("Molecule is not connected. Throwing exception.");
 
305
                        throw new CDKException(disconnectedMessage);
 
306
                } else
 
307
                {
 
308
                        logger.debug("Molecule is connected.");
 
309
                }
 
310
 
 
311
                /*
 
312
                 *  compute the minimum number of rings as
 
313
                 *  given by Frerejacque, Bull. Soc. Chim. Fr., 5, 1008 (1939)
 
314
                 */
 
315
                int nrOfEdges = molecule.getBondCount();
 
316
                //Vector2d ringSystemVector = null;
 
317
                //Vector2d newRingSystemVector = null;
 
318
                this.firstBondVector = firstBondVector;
 
319
                boolean templateMapped = false;
 
320
                double angle;
 
321
 
 
322
                /*
 
323
                 *  First we check if we can map any templates with predefined coordinates
 
324
                 *  Those are stored as MDL molfiles in data/templates
 
325
                 */
 
326
                if (useTemplates && (System.getProperty("java.version").indexOf("1.3.") == -1))
 
327
                {
 
328
                        logger.debug("Initializing TemplateHandler");
 
329
                        logger.debug("TemplateHander initialized");
 
330
                        logger.debug("Now starting Template Detection in Molecule...");
 
331
                        mappedSubstructures = getTemplateHandler().getMappedSubstructures(molecule);
 
332
                        templateMapped = mappedSubstructures.getAtomContainerCount() > 0;
 
333
                        logger.debug("Template Detection finished");
 
334
                        logger.debug("Number of found templates: " + mappedSubstructures.getAtomContainerCount());
 
335
                }
 
336
                                                                
 
337
                int expectedRingCount = nrOfEdges - molecule.getAtomCount() + 1;
 
338
                if (expectedRingCount > 0)
 
339
                {
 
340
                        logger.debug("*** Start of handling rings. ***");
 
341
                        /*
 
342
                         *  Get the smallest set of smallest rings on this molecule
 
343
                         */
 
344
                                                                                                SSSRFinder sssrf = new SSSRFinder(molecule);
 
345
 
 
346
                        sssr = sssrf.findSSSR();
 
347
                        if (sssr.getAtomContainerCount() < 1)
 
348
                        {
 
349
                                return;
 
350
                        }
 
351
                                                                                                
 
352
                        /*
 
353
                         * Order the rings because SSSRFinder.findSSSR() returns rings in an
 
354
                         * undeterministic order.
 
355
                         */
 
356
                        AtomContainerSetManipulator.sort(sssr);
 
357
                                                                                                
 
358
                        /*
 
359
                         *  Mark all the atoms from the ring system as "ISINRING"
 
360
                         */
 
361
                        markRingAtoms(sssr);
 
362
                        /*
 
363
                         *  Give a handle of our molecule to the ringPlacer
 
364
                         */
 
365
                        ringPlacer.setMolecule(molecule);
 
366
                        ringPlacer.checkAndMarkPlaced(sssr);
 
367
                        /*
 
368
                         *  Partition the smallest set of smallest rings into disconnected ring system.
 
369
                         *  The RingPartioner returns a Vector containing RingSets. Each of the RingSets contains
 
370
                         *  rings that are connected to each other either as bridged ringsystems, fused rings or
 
371
                         *  via spiro connections.
 
372
                         */
 
373
                        ringSystems = RingPartitioner.partitionRings(sssr);
 
374
                                                                                                
 
375
                        /*
 
376
                         *  We got our ring systems now
 
377
                         */
 
378
                                                                                                
 
379
                        /*
 
380
                         *  Do the layout for the first connected ring system ...
 
381
                         */
 
382
                        int largest = 0;
 
383
                        int largestSize = ((IRingSet) ringSystems.get(0)).getAtomContainerCount();
 
384
                        logger.debug("We have " + ringSystems.size() + " ring system(s).");
 
385
                        for (int f = 0; f < ringSystems.size(); f++)
 
386
                        {
 
387
                                logger.debug("RingSet " + f + " has size " + ((IRingSet) ringSystems.get(f)).getAtomContainerCount());
 
388
                                if (((IRingSet) ringSystems.get(f)).getAtomContainerCount() > largestSize)
 
389
                                {
 
390
                                        largestSize = ((IRingSet) ringSystems.get(f)).getAtomContainerCount();
 
391
                                        largest = f;
 
392
                                }
 
393
                        }
 
394
                        logger.debug("Largest RingSystem is at RingSet collection's position " + largest);
 
395
                        logger.debug("Size of Largest RingSystem: " + largestSize);
 
396
 
 
397
                        layoutRingSet(firstBondVector, (IRingSet) ringSystems.get(largest));
 
398
                        logger.debug("First RingSet placed");
 
399
                        /*
 
400
                         *  and do the placement of all the directly connected atoms of this ringsystem
 
401
                         */
 
402
                        ringPlacer.placeRingSubstituents((IRingSet) ringSystems.get(largest), bondLength);
 
403
 
 
404
                } else
 
405
                {
 
406
                        
 
407
                        logger.debug("*** Start of handling purely aliphatic molecules. ***");
 
408
                        /*
 
409
                         *  We are here because there are no rings in the molecule
 
410
                         *  so we get the longest chain in the molecule and placed in
 
411
                         *  on a horizontal axis
 
412
                         */
 
413
                        logger.debug("Searching initialLongestChain for this purely aliphatic molecule");
 
414
                        IAtomContainer longestChain = atomPlacer.getInitialLongestChain(molecule);
 
415
                        logger.debug("Found linear chain of length " + longestChain.getAtomCount());
 
416
                        logger.debug("Setting coordinated of first atom to 0,0");
 
417
                        longestChain.getAtom(0).setPoint2d(new Point2d(0, 0));
 
418
                        longestChain.getAtom(0).setFlag(CDKConstants.ISPLACED, true);
 
419
 
 
420
                        /*
 
421
                         *  place the first bond such that the whole chain will be horizontally
 
422
                         *  alligned on the x axis
 
423
                         */
 
424
                        angle = Math.toRadians(-30);
 
425
                        logger.debug("Attempting to place the first bond such that the whole chain will be horizontally alligned on the x axis");
 
426
                        if (firstBondVector != null)
 
427
                                atomPlacer.placeLinearChain(longestChain, firstBondVector, bondLength);
 
428
                        else
 
429
                                atomPlacer.placeLinearChain(longestChain, new Vector2d(Math.cos(angle), Math.sin(angle)), bondLength);
 
430
                        logger.debug("Placed longest aliphatic chain");
 
431
                }
 
432
 
 
433
                /*
 
434
                 *  Now, do the layout of the rest of the molecule
 
435
                 */
 
436
                do
 
437
                {
 
438
                        safetyCounter++;
 
439
                        logger.debug("*** Start of handling the rest of the molecule. ***");
 
440
                        /*
 
441
                         *  do layout for all aliphatic parts of the molecule which are
 
442
                         *  connected to the parts which have already been laid out.
 
443
                         */
 
444
                        handleAliphatics();
 
445
                        /*
 
446
                         *  do layout for the next ring aliphatic parts of the molecule which are
 
447
                         *  connected to the parts which have already been laid out.
 
448
                         */
 
449
                        layoutNextRingSystem();
 
450
                } while (!atomPlacer.allPlaced(molecule) && safetyCounter <= molecule.getAtomCount());
 
451
 
 
452
                fixRest();
 
453
                new OverlapResolver().resolveOverlap(molecule, sssr);
 
454
        }
 
455
 
 
456
 
 
457
        /**
 
458
         *  The main method of this StructurDiagramGenerator. Assign a molecule to the
 
459
         *  StructurDiagramGenerator, call the generateCoordinates() method and get
 
460
         *  your molecule back.
 
461
         *
 
462
         *  @throws java.lang.Exception if an error occurs
 
463
         */
 
464
        public void generateCoordinates() throws java.lang.Exception
 
465
        {
 
466
                generateCoordinates(new Vector2d(0, 1));
 
467
        }
 
468
 
 
469
 
 
470
        /**
 
471
         *  Does a layout of all the rings in a given connected RingSet. Uses a TemplateHandler
 
472
         *  to treat templated mapped substructures differently if <code>useTemplates</code> is
 
473
         *  set true.
 
474
         * 
 
475
         * @param firstBondVector A vector giving the placement for the first bond
 
476
         * @param rs The connected RingSet for which the layout is to be
 
477
         *           done
 
478
         * @throws java.lang.Exception if an error occurs
 
479
         */
 
480
        private void layoutRingSet(Vector2d firstBondVector, IRingSet rs) throws Exception
 
481
        {
 
482
                IAtomContainer sharedAtoms;
 
483
                Vector2d ringCenterVector;
 
484
                int thisRing;
 
485
                logger.debug("Start of layoutRingSet");
 
486
 
 
487
                /*
 
488
                 * First we check if we can map any templates with predifined coordinates.
 
489
                 * All mapped substructures are saved in: this.mappedSubstructures 
 
490
                 */
 
491
                if (useTemplates && mappedSubstructures.getAtomContainerCount() > 0 && System.getProperty("java.version").indexOf("1.3.") == -1) {
 
492
                        /*
 
493
                         * Find mapped substructures
 
494
                         */
 
495
                        for (Iterator substructureIterator = mappedSubstructures.atomContainers(); substructureIterator.hasNext(); ) {
 
496
                                IAtomContainer substructure = (IAtomContainer) substructureIterator.next();
 
497
                                boolean substructureMapped = false;
 
498
                                for (Iterator ringSetIterator = rs.atomContainers(); ringSetIterator.hasNext() && !substructureMapped; ) {
 
499
                                        IRing ring = (IRing) ringSetIterator.next();
 
500
                                        for (Iterator atomIterator = ring.atoms(); atomIterator.hasNext() && !substructureMapped; ) {
 
501
                                                IAtom atom = (IAtom) atomIterator.next();
 
502
                                                        if (substructure.contains(atom))
 
503
                                                                substructureMapped = true;
 
504
                                        }
 
505
                                }
 
506
                                /*
 
507
                                 * Layout a found mapped substructure
 
508
                                 */
 
509
                                if (substructureMapped) {
 
510
                                        boolean mapped = getTemplateHandler().mapTemplateExact(substructure);
 
511
                                        if (!mapped)
 
512
                                                logger.warn("A supposedly matched substructure failed to match.");
 
513
                                        else {
 
514
                                                // Mark substructure atoms as CDKConstants.ISPLACED
 
515
                                                for (Iterator iterator = substructure.atoms(); iterator.hasNext(); ) {
 
516
                                                        IAtom atom = (IAtom) iterator.next();
 
517
                                                        atom.setFlag(CDKConstants.ISPLACED, true);
 
518
                                                }
 
519
                                                // Mark rings of substrucure as CDKConstants.ISPLACED
 
520
                                                ringPlacer.checkAndMarkPlaced(rs);
 
521
                                        }
 
522
                                }
 
523
                        }
 
524
                }
 
525
                
 
526
                /*
 
527
                 * Now layout the rest of this ring system
 
528
                 */
 
529
 
 
530
                /*
 
531
                 *  Get the most complex ring in this RingSet
 
532
                 */
 
533
                IRing ring = RingSetManipulator.getMostComplexRing(rs);
 
534
                int i = 0;
 
535
                
 
536
                /*
 
537
                 *  Place the most complex ring at the origin of the coordinate system
 
538
                 */
 
539
                if (!ring.getFlag(CDKConstants.ISPLACED))
 
540
                {
 
541
                        sharedAtoms = placeFirstBond((IBond) ring.getBond(i), firstBondVector);
 
542
                        /*
 
543
                         *  Call the method which lays out the new ring.
 
544
                         */
 
545
                        ringCenterVector = ringPlacer.getRingCenterOfFirstRing(ring, firstBondVector, bondLength);
 
546
                        ringPlacer.placeRing(ring, sharedAtoms, GeometryToolsInternalCoordinates.get2DCenter(sharedAtoms), ringCenterVector, bondLength);
 
547
                        /*
 
548
                         *  Mark the ring as placed
 
549
                         */
 
550
                        ring.setFlag(CDKConstants.ISPLACED, true);
 
551
                }
 
552
                /*
 
553
                 *  Place all other rings in this ringsystem.
 
554
                 */
 
555
                thisRing = 0;
 
556
                do
 
557
                {
 
558
                        if (ring.getFlag(CDKConstants.ISPLACED))
 
559
                        {
 
560
                                ringPlacer.placeConnectedRings(rs, ring, RingPlacer.FUSED, bondLength);
 
561
                                ringPlacer.placeConnectedRings(rs, ring, RingPlacer.BRIDGED, bondLength);
 
562
                                ringPlacer.placeConnectedRings(rs, ring, RingPlacer.SPIRO, bondLength);
 
563
                        }
 
564
                        thisRing++;
 
565
                        if (thisRing == rs.getAtomContainerCount())
 
566
                        {
 
567
                                thisRing = 0;
 
568
                        }
 
569
                        ring = (IRing) rs.getAtomContainer(thisRing);
 
570
                } while (!allPlaced(rs));
 
571
                logger.debug("End of layoutRingSet");
 
572
        }
 
573
 
 
574
 
 
575
 
 
576
        /**
 
577
         * Does a layout of all aliphatic parts connected to the parts of the molecule
 
578
         * that have already been laid out. Starts at the first bond with unplaced
 
579
         * neighbours and stops when a ring is encountered.
 
580
         * 
 
581
         * @throws org.openscience.cdk.exception.CDKException if an error occurs
 
582
         */
 
583
        private void handleAliphatics() throws org.openscience.cdk.exception.CDKException
 
584
        {
 
585
                logger.debug("Start of handleAliphatics");
 
586
 
 
587
                int safetyCounter = 0;
 
588
                IAtomContainer unplacedAtoms = null;
 
589
                IAtomContainer placedAtoms = null;
 
590
                IAtomContainer longestUnplacedChain = null;
 
591
                IAtom atom = null;
 
592
 
 
593
                Vector2d direction = null;
 
594
                Vector2d startVector = null;
 
595
                boolean done;
 
596
                do
 
597
                {
 
598
                        safetyCounter++;
 
599
                        done = false;
 
600
                        atom = getNextAtomWithAliphaticUnplacedNeigbors();
 
601
                        if (atom != null)
 
602
                        {
 
603
                                unplacedAtoms = getUnplacedAtoms(atom);
 
604
                                placedAtoms = getPlacedAtoms(atom);
 
605
 
 
606
                                longestUnplacedChain = atomPlacer.getLongestUnplacedChain(molecule, atom);
 
607
                                
 
608
                                logger.debug("---start of longest unplaced chain---");
 
609
                                try
 
610
                                {
 
611
                                        logger.debug("Start at atom no. " + (molecule.getAtomNumber(atom) + 1));
 
612
                                        logger.debug(atomPlacer.listNumbers(molecule, longestUnplacedChain));
 
613
                                } catch (Exception exc) {
 
614
                                        logger.debug(exc);
 
615
                                }
 
616
                                logger.debug("---end of longest unplaced chain---");
 
617
 
 
618
                                if (longestUnplacedChain.getAtomCount() > 1)
 
619
                                {
 
620
 
 
621
                                        if (placedAtoms.getAtomCount() > 1)
 
622
                                        {
 
623
                                                logger.debug("More than one atoms placed already");
 
624
                                                logger.debug("trying to place neighbors of atom " + (molecule.getAtomNumber(atom) + 1));
 
625
                                                atomPlacer.distributePartners(atom, placedAtoms, GeometryToolsInternalCoordinates.get2DCenter(placedAtoms), unplacedAtoms, bondLength);
 
626
                                                direction = new Vector2d(longestUnplacedChain.getAtom(1).getPoint2d());
 
627
                                                startVector = new Vector2d(atom.getPoint2d());
 
628
                                                direction.sub(startVector);
 
629
                                                logger.debug("Done placing neighbors of atom " + (molecule.getAtomNumber(atom) + 1));
 
630
                                        } else
 
631
                                        {
 
632
                                                logger.debug("Less than or equal one atoms placed already");
 
633
                                                logger.debug("Trying to get next bond vector.");
 
634
                                                direction = atomPlacer.getNextBondVector(atom, placedAtoms.getAtom(0), GeometryToolsInternalCoordinates.get2DCenter(molecule),true);
 
635
 
 
636
                                        }
 
637
 
 
638
                                        for (int f = 1; f < longestUnplacedChain.getAtomCount(); f++)
 
639
                                        {
 
640
                                                longestUnplacedChain.getAtom(f).setFlag(CDKConstants.ISPLACED, false);
 
641
                                        }
 
642
                                        atomPlacer.placeLinearChain(longestUnplacedChain, direction, bondLength);
 
643
 
 
644
                                } else
 
645
                                {
 
646
                                        done = true;
 
647
                                }
 
648
                        } else
 
649
                        {
 
650
                                done = true;
 
651
                        }
 
652
                } while (!done && safetyCounter <= molecule.getAtomCount());
 
653
 
 
654
                logger.debug("End of handleAliphatics");
 
655
        }
 
656
 
 
657
 
 
658
        /**
 
659
         *  Does the layout for the next RingSystem that is connected to those parts of
 
660
         *  the molecule that have already been laid out. Finds the next ring with an
 
661
         *  unplaced ring atom and lays out this ring. Then lays out the ring substituents
 
662
         *  of this ring. Then moves and rotates the laid out ring to match the position
 
663
         *  of its attachment bond to the rest of the molecule.
 
664
         *
 
665
         *  @throws java.lang.Exception if an error occurs
 
666
         */
 
667
        private void layoutNextRingSystem() throws Exception
 
668
        {
 
669
                logger.debug("Start of layoutNextRingSystem()");
 
670
 
 
671
                resetUnplacedRings();
 
672
                IAtomContainer tempAc = atomPlacer.getPlacedAtoms(molecule);
 
673
                logger.debug("Finding attachment bond to already placed part...");
 
674
                IBond nextRingAttachmentBond = getNextBondWithUnplacedRingAtom();
 
675
                if (nextRingAttachmentBond != null)
 
676
                {
 
677
                        logger.debug("...bond found.");
 
678
                                                                                                
 
679
                        /*
 
680
                         * Get the chain and the ring atom that are connected to where we are comming from.
 
681
                         * Both are connected by nextRingAttachmentBond.
 
682
                         */
 
683
                        IAtom ringAttachmentAtom = getRingAtom(nextRingAttachmentBond);
 
684
                        IAtom chainAttachmentAtom = getOtherBondAtom(ringAttachmentAtom, nextRingAttachmentBond);
 
685
                        
 
686
                        /*
 
687
                         * Get ring system which ringAttachmentAtom is part of
 
688
                         */
 
689
                        IRingSet nextRingSystem = getRingSystemOfAtom(ringSystems, ringAttachmentAtom);
 
690
 
 
691
                        /*
 
692
                         * Get all rings of nextRingSytem as one IAtomContainer
 
693
                         */
 
694
                        IAtomContainer ringSystem = tempAc.getBuilder().newAtomContainer();
 
695
                        for (Iterator containers = RingSetManipulator.getAllAtomContainers(nextRingSystem).iterator(); containers.hasNext(); )
 
696
                                ringSystem.add((IAtomContainer) containers.next());
 
697
                                                                                                
 
698
                        /*
 
699
                         * Save coordinates of ringAttachmentAtom and chainAttachmentAtom
 
700
                         */
 
701
                        Point2d oldRingAttachmentAtomPoint = ringAttachmentAtom.getPoint2d();
 
702
                        Point2d oldChainAttachmentAtomPoint = chainAttachmentAtom.getPoint2d();
 
703
                        
 
704
                        /*
 
705
                         *  Do the layout of the next ring system
 
706
                         */
 
707
                        layoutRingSet(firstBondVector, nextRingSystem);
 
708
                                                                                                
 
709
                        /*
 
710
                         *  Place all the substituents of next ring system
 
711
                         */
 
712
                        atomPlacer.markNotPlaced(tempAc);
 
713
                        IAtomContainer placedRingSubstituents = ringPlacer.placeRingSubstituents(nextRingSystem, bondLength);
 
714
                        ringSystem.add(placedRingSubstituents);
 
715
                        atomPlacer.markPlaced(tempAc);
 
716
                                                                                                
 
717
                        /*
 
718
                         * Move and rotate the laid out ring system to match the geometry of the
 
719
                         * attachment bond
 
720
                         */
 
721
                        logger.debug("Computing translation/rotation of new ringset to fit old attachment bond orientation...");
 
722
 
 
723
                        // old placed ring atom coordinate
 
724
                        Point2d oldPoint2 = oldRingAttachmentAtomPoint;
 
725
                        // old placed substituent atom coordinate
 
726
                        Point2d oldPoint1 = oldChainAttachmentAtomPoint;
 
727
 
 
728
                        // new placed ring atom coordinate
 
729
                        Point2d newPoint2 = ringAttachmentAtom.getPoint2d();
 
730
                        // new placed substituent atom coordinate
 
731
                        Point2d newPoint1 = chainAttachmentAtom.getPoint2d();
 
732
 
 
733
                        logger.debug("oldPoint1: " + oldPoint1);
 
734
                        logger.debug("oldPoint2: " + oldPoint2);
 
735
                        logger.debug("newPoint1: " + newPoint1);
 
736
                        logger.debug("newPoint2: " + newPoint2);
 
737
 
 
738
                        double oldAngle = GeometryToolsInternalCoordinates.getAngle(oldPoint2.x - oldPoint1.x, oldPoint2.y - oldPoint1.y);
 
739
                        double newAngle = GeometryToolsInternalCoordinates.getAngle(newPoint2.x - newPoint1.x, newPoint2.y - newPoint1.y);
 
740
                        double angleDiff = oldAngle - newAngle;
 
741
 
 
742
                        logger.debug("oldAngle: " + oldAngle + ", newAngle: " + newAngle + "; diff = " + angleDiff);
 
743
 
 
744
                        Vector2d translationVector = new Vector2d(oldPoint1);
 
745
                        translationVector.sub(new Vector2d(newPoint1));
 
746
 
 
747
                        /*
 
748
                         * Move to fit old attachment bond orientation
 
749
                         */
 
750
                        GeometryToolsInternalCoordinates.translate2D(ringSystem, translationVector);
 
751
 
 
752
                        /*
 
753
                         * Rotate to fit old attachment bond orientation
 
754
                         */
 
755
                        GeometryToolsInternalCoordinates.rotate(ringSystem, oldPoint1, angleDiff);
 
756
 
 
757
                        logger.debug("...done translating/rotating new ringset to fit old attachment bond orientation.");
 
758
                }
 
759
                else
 
760
                        logger.debug("...no bond found");
 
761
 
 
762
                logger.debug("End of layoutNextRingSystem()");
 
763
        }
 
764
 
 
765
 
 
766
        /**
 
767
         *  Returns an AtomContainer with all unplaced atoms connected to a given
 
768
         *  atom
 
769
         *
 
770
         *  @param  atom  The Atom whose unplaced bonding partners are to be returned
 
771
         *  @return       an AtomContainer with all unplaced atoms connected to a
 
772
         *                given atom
 
773
         */
 
774
        private IAtomContainer getUnplacedAtoms(IAtom atom)
 
775
        {
 
776
                IAtomContainer unplacedAtoms = atom.getBuilder().newAtomContainer();
 
777
                java.util.List bonds = molecule.getConnectedBondsList(atom);
 
778
                IAtom connectedAtom;
 
779
                for (int f = 0; f < bonds.size(); f++)
 
780
                {
 
781
                        connectedAtom = ((IBond)bonds.get(f)).getConnectedAtom(atom);
 
782
                        if (!connectedAtom.getFlag(CDKConstants.ISPLACED))
 
783
                        {
 
784
                                unplacedAtoms.addAtom(connectedAtom);
 
785
                        }
 
786
                }
 
787
                return unplacedAtoms;
 
788
        }
 
789
 
 
790
 
 
791
        /**
 
792
         *  Returns an AtomContainer with all placed atoms connected to a given
 
793
         *  atom
 
794
         *
 
795
         *  @param  atom  The Atom whose placed bonding partners are to be returned
 
796
         *  @return       an AtomContainer with all placed atoms connected to a given
 
797
         *                atom
 
798
         */
 
799
        private IAtomContainer getPlacedAtoms(IAtom atom)
 
800
        {
 
801
                IAtomContainer placedAtoms = atom.getBuilder().newAtomContainer();
 
802
                java.util.List bonds = molecule.getConnectedBondsList(atom);
 
803
                IAtom connectedAtom;
 
804
                for (int f = 0; f < bonds.size(); f++)
 
805
                {
 
806
                        connectedAtom = ((IBond)bonds.get(f)).getConnectedAtom(atom);
 
807
                        if (connectedAtom.getFlag(CDKConstants.ISPLACED))
 
808
                        {
 
809
                                placedAtoms.addAtom(connectedAtom);
 
810
                        }
 
811
                }
 
812
                return placedAtoms;
 
813
        }
 
814
 
 
815
 
 
816
        /**
 
817
         *  Returns the next atom with unplaced aliphatic neighbors
 
818
         *
 
819
         *  @return    the next atom with unplaced aliphatic neighbors
 
820
         */
 
821
        private IAtom getNextAtomWithAliphaticUnplacedNeigbors()
 
822
        {
 
823
                IBond bond;
 
824
                for (int f = 0; f < molecule.getBondCount(); f++)
 
825
                {
 
826
                        bond = molecule.getBond(f);
 
827
                        
 
828
                        if (bond.getAtom(1).getFlag(CDKConstants.ISPLACED) &&
 
829
                                !bond.getAtom(0).getFlag(CDKConstants.ISPLACED))
 
830
                        {
 
831
                                return bond.getAtom(1);
 
832
                        }
 
833
 
 
834
                        if (bond.getAtom(0).getFlag(CDKConstants.ISPLACED) &&
 
835
                                !bond.getAtom(1).getFlag(CDKConstants.ISPLACED))
 
836
                        {
 
837
                                return bond.getAtom(0);
 
838
                        }
 
839
                }
 
840
                return null;
 
841
        }
 
842
 
 
843
 
 
844
        /**
 
845
         *  Returns the next bond with an unplaced ring atom
 
846
         *
 
847
         *  @return    the next bond with an unplaced ring atom
 
848
         */
 
849
        private IBond getNextBondWithUnplacedRingAtom() {
 
850
                Iterator bonds = molecule.bonds();
 
851
                while (bonds.hasNext()) {
 
852
                        IBond bond = (IBond) bonds.next();
 
853
 
 
854
                        if (bond.getAtom(0).getPoint2d() != null &&
 
855
                                        bond.getAtom(1).getPoint2d() != null) {
 
856
                                if (bond.getAtom(1).getFlag(CDKConstants.ISPLACED) &&
 
857
                                                !bond.getAtom(0).getFlag(CDKConstants.ISPLACED) &&
 
858
                                                bond.getAtom(0).getFlag(CDKConstants.ISINRING)) {
 
859
                                        return bond;
 
860
                                }
 
861
 
 
862
                                if (bond.getAtom(0).getFlag(CDKConstants.ISPLACED) &&
 
863
                                                !bond.getAtom(1).getFlag(CDKConstants.ISPLACED) &&
 
864
                                                bond.getAtom(1).getFlag(CDKConstants.ISINRING)) {
 
865
                                        return bond;
 
866
                                }
 
867
                        }
 
868
                }
 
869
                return null;
 
870
        }
 
871
 
 
872
 
 
873
        /**
 
874
         *  Places the first bond of the first ring such that one atom is at (0,0) and
 
875
         *  the other one at the position given by bondVector
 
876
         *
 
877
         *  @param  bondVector  A 2D vector to point to the position of the second bond
 
878
         *                      atom
 
879
         *  @param  bond        the bond to lay out
 
880
         *  @return             an IAtomContainer with the atoms of the bond and the bond itself
 
881
         */
 
882
        private IAtomContainer placeFirstBond(IBond bond, Vector2d bondVector)
 
883
        {
 
884
                IAtomContainer sharedAtoms = null;
 
885
                try
 
886
                {
 
887
                        bondVector.normalize();
 
888
                        logger.debug("placeFirstBondOfFirstRing->bondVector.length():" + bondVector.length());
 
889
                        bondVector.scale(bondLength);
 
890
                        logger.debug("placeFirstBondOfFirstRing->bondVector.length() after scaling:" + bondVector.length());
 
891
                        IAtom atom;
 
892
                        Point2d point = new Point2d(0, 0);
 
893
                        atom = bond.getAtom(0);
 
894
                        logger.debug("Atom 1 of first Bond: " + (molecule.getAtomNumber(atom) + 1));
 
895
                        atom.setPoint2d(point);
 
896
                        atom.setFlag(CDKConstants.ISPLACED, true);
 
897
                        point = new Point2d(0, 0);
 
898
                        atom = bond.getAtom(1);
 
899
                        logger.debug("Atom 2 of first Bond: " + (molecule.getAtomNumber(atom) + 1));
 
900
                        point.add(bondVector);
 
901
                        atom.setPoint2d(point);
 
902
                        atom.setFlag(CDKConstants.ISPLACED, true);
 
903
                        /*
 
904
                         *  The new ring is layed out relativ to some shared atoms that have already been
 
905
                         *  placed. Usually this is another ring, that has already been draw and to which the new
 
906
                         *  ring is somehow connected, or some other system of atoms in an aliphatic chain.
 
907
                         *  In this case, it's the first bond that we layout by hand.
 
908
                         */
 
909
                        sharedAtoms = atom.getBuilder().newAtomContainer();
 
910
                        sharedAtoms.addBond(bond);
 
911
                        sharedAtoms.addAtom(bond.getAtom(0));
 
912
                        sharedAtoms.addAtom(bond.getAtom(1));
 
913
                } catch (Exception exc) {
 
914
                        logger.debug(exc);
 
915
                }
 
916
                return sharedAtoms;
 
917
        }
 
918
 
 
919
 
 
920
        /**
 
921
         *  This method will go as soon as the rest works. It just assignes Point2d's
 
922
         *  of position (0,0) so that the molecule can be drawn.
 
923
         */
 
924
        private void fixRest()
 
925
        {
 
926
                IAtom atom = null;
 
927
                for (int f = 0; f < molecule.getAtomCount(); f++)
 
928
                {
 
929
                        atom = molecule.getAtom(f);
 
930
                        if (atom.getPoint2d() == null)
 
931
                        {
 
932
                                atom.setPoint2d(new Point2d(0, 0));
 
933
                        }
 
934
                }
 
935
        }
 
936
 
 
937
        /**
 
938
         *  This method will go as soon as the rest works. It just assignes Point2d's
 
939
         *  of position (0,0) so that the molecule can be drawn.
 
940
         *  @param molecule the molecule to fix
 
941
         *  @return the fixed molecule
 
942
         */
 
943
        private IMolecule fixMol(IMolecule molecule)
 
944
        {
 
945
                IAtom atom = null;
 
946
                for (int f = 0; f < molecule.getAtomCount(); f++)
 
947
                {
 
948
                        atom = molecule.getAtom(f);
 
949
                        if (atom.getPoint2d() == null)
 
950
                        {
 
951
                                atom.setPoint2d(new Point2d(0, 0));
 
952
                        }
 
953
                }
 
954
                                                                return molecule;
 
955
        }        
 
956
 
 
957
        /**
 
958
         *  Initializes all rings in RingSet rs as not placed
 
959
         *
 
960
         *  @param  rs  The RingSet to be initialized
 
961
         */
 
962
//      private void markNotPlaced(IRingSet rs)
 
963
//      {
 
964
//              for (int f = 0; f < rs.size(); f++)
 
965
//              {
 
966
//                      ((IRing) rs.get(f)).setFlag(CDKConstants.ISPLACED, false);
 
967
//              }
 
968
//      }
 
969
 
 
970
 
 
971
        /**
 
972
         *  Are all rings in the Vector placed?
 
973
         *
 
974
         *  @param  rings  The Vector to be checked
 
975
         *  @return        true if all rings are placed, false otherwise
 
976
         */
 
977
        private boolean allPlaced(IRingSet rings)
 
978
        {
 
979
                for (int f = 0; f < rings.getAtomContainerCount(); f++)
 
980
                {
 
981
                        if (!((IRing) rings.getAtomContainer(f)).getFlag(CDKConstants.ISPLACED))
 
982
                        {
 
983
                                logger.debug("allPlaced->Ring " + f + " not placed");
 
984
                                return false;
 
985
                        }
 
986
                }
 
987
                return true;
 
988
        }
 
989
 
 
990
 
 
991
        /**
 
992
         *  Mark all atoms in the molecule as being part of a ring
 
993
         *
 
994
         *  @param  rings  an IRingSet with the rings to process
 
995
         */
 
996
        private void markRingAtoms(IRingSet rings)
 
997
        {
 
998
                IRing ring = null;
 
999
                for (int i = 0; i < rings.getAtomContainerCount(); i++)
 
1000
                {
 
1001
                        ring = (IRing) rings.getAtomContainer(i);
 
1002
                        for (int j = 0; j < ring.getAtomCount(); j++)
 
1003
                        {
 
1004
                                ring.getAtom(j).setFlag(CDKConstants.ISINRING, true);
 
1005
                        }
 
1006
                }
 
1007
        }
 
1008
 
 
1009
 
 
1010
        /**
 
1011
         *  Get the unplaced ring atom in this bond
 
1012
         *
 
1013
         *  @param  bond  the bond to be search for the unplaced ring atom
 
1014
         *  @return       the unplaced ring atom in this bond
 
1015
         */
 
1016
        private IAtom getRingAtom(IBond bond)
 
1017
        {
 
1018
                if (bond.getAtom(0).getFlag(CDKConstants.ISINRING) &&
 
1019
                                !bond.getAtom(0).getFlag(CDKConstants.ISPLACED))
 
1020
                {
 
1021
                        return bond.getAtom(0);
 
1022
                }
 
1023
                if (bond.getAtom(1).getFlag(CDKConstants.ISINRING) &&
 
1024
                                !bond.getAtom(1).getFlag(CDKConstants.ISPLACED))
 
1025
                {
 
1026
                        return bond.getAtom(1);
 
1027
                }
 
1028
                return null;
 
1029
        }
 
1030
 
 
1031
 
 
1032
        /**
 
1033
         *  Get the ring system of which the given atom is part of
 
1034
         *
 
1035
         *  @param  ringSystems  a List of ring systems to be searched
 
1036
         *  @param  ringAtom     the ring atom to be search in the ring system.
 
1037
         *  @return              the ring system the given atom is part of
 
1038
         */
 
1039
        private IRingSet getRingSystemOfAtom(List ringSystems, IAtom ringAtom)
 
1040
        {
 
1041
                IRingSet ringSet = null;
 
1042
                for (int f = 0; f < ringSystems.size(); f++)
 
1043
                {
 
1044
                        ringSet = (IRingSet) ringSystems.get(f);
 
1045
                        if (ringSet.contains(ringAtom))
 
1046
                        {
 
1047
                                return ringSet;
 
1048
                        }
 
1049
                }
 
1050
                return null;
 
1051
        }
 
1052
 
 
1053
 
 
1054
        /**
 
1055
         *  Set all the atoms in unplaced rings to be unplaced
 
1056
         */
 
1057
        private void resetUnplacedRings()
 
1058
        {
 
1059
                IRing ring = null;
 
1060
                if (sssr == null)
 
1061
                {
 
1062
                        return;
 
1063
                }
 
1064
                int unplacedCounter = 0;
 
1065
                for (int f = 0; f < sssr.getAtomContainerCount(); f++)
 
1066
                {
 
1067
                        ring = (IRing) sssr.getAtomContainer(f);
 
1068
                        if (!ring.getFlag(CDKConstants.ISPLACED))
 
1069
                        {
 
1070
                                logger.debug("Ring with " + ring.getAtomCount() + " atoms is not placed.");
 
1071
                                unplacedCounter++;
 
1072
                                for (int g = 0; g < ring.getAtomCount(); g++)
 
1073
                                {
 
1074
                                        ring.getAtom(g).setFlag(CDKConstants.ISPLACED, false);
 
1075
                                }
 
1076
                        }
 
1077
                }
 
1078
                logger.debug("There are " + unplacedCounter + " unplaced Rings.");
 
1079
        }
 
1080
 
 
1081
 
 
1082
        /**
 
1083
         *  Set the bond length used for laying out the molecule.
 
1084
         *  The defaut value is 1.5.
 
1085
         *
 
1086
         *  @param  bondLength  The new bondLength value
 
1087
         */
 
1088
        public void setBondLength(double bondLength)
 
1089
        {
 
1090
                this.bondLength = bondLength;
 
1091
        }
 
1092
                                
 
1093
        /**
 
1094
         * Returns the other atom of the bond.
 
1095
         * Expects bond to have only two atoms.
 
1096
         * Returns null if the given atom is not part of the given bond.
 
1097
         * 
 
1098
         * @param atom the atom we already have
 
1099
         * @param bond the bond
 
1100
         * @return the other atom of the bond
 
1101
         */
 
1102
        public IAtom getOtherBondAtom(IAtom atom, IBond bond) {
 
1103
                if (!bond.contains(atom))
 
1104
                        return null;
 
1105
                if (bond.getAtom(0).equals(atom))
 
1106
                        return bond.getAtom(1);
 
1107
                else
 
1108
                        return bond.getAtom(0);
 
1109
        }
 
1110
 
 
1111
}