3
* $Date: 2007-04-16 10:40:19 +0200 (Mon, 16 Apr 2007) $
6
* Copyright (C) 2005-2007 Christian Hoppe <chhoppe@users.sf.net>
8
* Contact: cdk-devel@lists.sourceforge.net
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public License
12
* as published by the Free Software Foundation; either version 2.1
13
* of the License, or (at your option) any later version.
14
* All we ask is that proper credit is given for our work, which includes
15
* - but is not limited to - adding the above copyright notice to the beginning
16
* of your source code files, and to any copyright notice that you may distribute
17
* with programs based on this work.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU Lesser General Public License for more details.
24
* You should have received a copy of the GNU Lesser General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29
package org.openscience.cdk.modeling.builder3d;
31
import java.io.IOException;
32
import java.util.Hashtable;
33
import java.util.Vector;
35
import javax.vecmath.AxisAngle4d;
36
import javax.vecmath.Matrix3d;
37
import javax.vecmath.Point3d;
38
import javax.vecmath.Vector3d;
40
import org.openscience.cdk.interfaces.IAtom;
41
import org.openscience.cdk.interfaces.IAtomContainer;
42
import org.openscience.cdk.interfaces.IBond;
43
import org.openscience.cdk.CDKConstants;
46
* A set of static utility classes for geometric calculations on Atoms.
48
*@author Peter Murray-Rust,chhoppe,egonw
49
*@cdk.created 2003-??-??
50
* @cdk.module builder3d
52
public class AtomTetrahedralLigandPlacer3D {
54
private Hashtable pSet = null;
55
private final double DEFAULT_BOND_LENGTH_H = 1.0;
56
//private final double DEFAULT_BOND_LENGTH_HA = 1.3;
58
public final double TETRAHEDRAL_ANGLE =
59
2.0 * Math.acos(1.0 / Math.sqrt(3.0));
61
private final double SP2_ANGLE = 120 * Math.PI / 180;
62
private final double SP_ANGLE = Math.PI;
64
final static Vector3d XV = new Vector3d(1.0, 0.0, 0.0);
65
final static Vector3d YV = new Vector3d(0.0, 1.0, 0.0);
69
* Constructor for the AtomTetrahedralLigandPlacer3D object
71
AtomTetrahedralLigandPlacer3D() { }
75
* Constructor for the setParameterSet object
77
*@param moleculeParameter Description of the Parameter
79
public void setParameterSet(Hashtable moleculeParameter) {
80
pSet = moleculeParameter;
85
* Generate coordinates for all atoms which are singly bonded and have no
86
* coordinates. This is useful when hydrogens are present but have no coords.
87
* It knows about C, O, N, S only and will give tetrahedral or trigonal
88
* geometry elsewhere. Bond lengths are computed from covalent radii or taken
89
* out of a paramter set if available. Angles are tetrahedral or trigonal
91
*@param atomContainer the set of atoms involved
92
*@exception Exception Description of the Exception
93
*@cdk.keyword coordinate calculation
94
*@cdk.keyword 3D model
96
public void add3DCoordinatesForSinglyBondedLigands(IAtomContainer atomContainer) throws Exception {
97
IAtomContainer noCoords = new org.openscience.cdk.AtomContainer();
98
IAtomContainer withCoords = new org.openscience.cdk.AtomContainer();
102
for (int i = 0; i < atomContainer.getAtomCount(); i++) {
103
refAtom = atomContainer.getAtom(i);
104
if (!refAtom.getSymbol().equals("H") && hasUnsetNeighbour(refAtom, atomContainer)) {
105
noCoords = getUnsetAtomsInAtomContainer(refAtom, atomContainer);
106
withCoords = getPlacedAtomsInAtomContainer(refAtom, atomContainer);
107
if (withCoords.getAtomCount() > 0) {
108
atomC = getPlacedHeavyAtomInAtomContainer(withCoords.getAtom(0), refAtom, atomContainer);
110
if (refAtom.getFormalNeighbourCount() == 0 && refAtom.getSymbol().equals("C")) {
111
nwanted = noCoords.getAtomCount();
112
} else if (refAtom.getFormalNeighbourCount() == 0 && !refAtom.getSymbol().equals("C")) {
115
nwanted = refAtom.getFormalNeighbourCount() - withCoords.getAtomCount();
117
Point3d[] newPoints = get3DCoordinatesForLigands(refAtom,
118
noCoords, withCoords, atomC, nwanted, DEFAULT_BOND_LENGTH_H, -1);
119
for (int j = 0; j < noCoords.getAtomCount(); j++) {
120
IAtom ligand = noCoords.getAtom(j);
121
Point3d newPoint = rescaleBondLength(refAtom, ligand, newPoints[j]);
122
ligand.setPoint3d(newPoint);
123
ligand.setFlag(CDKConstants.ISPLACED, true);
126
noCoords.removeAllElements();
127
withCoords.removeAllElements();
134
* Rescales Point2 so that length 1-2 is sum of covalent radii.
135
* If covalent radii cannot be found, use bond length of 1.0
137
*@param atom1 stationary atom
138
*@param atom2 moveable atom
139
*@param point2 coordinates for atom 2
140
*@return new coords for atom 2
141
*@exception Exception Description of the Exception
143
public Point3d rescaleBondLength(IAtom atom1, IAtom atom2, Point3d point2) throws Exception {
144
Point3d point1 = atom1.getPoint3d();
145
double d1 = atom1.getCovalentRadius();
146
double d2 = atom2.getCovalentRadius();
147
// in case we have no covalent radii, set to 1.0
148
double distance = (d1 < 0.1 || d2 < 0.1) ? 1.0 :
149
atom1.getCovalentRadius() + atom2.getCovalentRadius();
151
distance = getDistanceValue(atom1.getAtomTypeName(), atom2.getAtomTypeName());
153
Vector3d vect = new Vector3d(point2);
156
vect.scale(distance);
157
Point3d newPoint = new Point3d(point1);
164
* Adds 3D coordinates for singly-bonded ligands of a reference atom (A).
165
* Initially designed for hydrogens. The ligands of refAtom are identified and
166
* those with 3D coordinates used to generate the new points. (This allows
167
* strucures with partially known 3D coordinates to be used, as when groups
168
* are added.) "Bent" and "non-planar" groups can be formed by taking a subset
169
* of the calculated points. Thus R-NH2 could use 2 of the 3 points calculated
170
* from (1,iii) nomenclature: A is point to which new ones are "attached". A
171
* may have ligands B, C... B may have ligands J, K.. points X1, X2... are
172
* returned The cases (see individual routines, which use idealised geometry
173
* by default): (0) zero ligands of refAtom. The resultant points are randomly
174
* oriented: (i) 1 points required; +x,0,0 (ii) 2 points: use +x,0,0 and
175
* -x,0,0 (iii) 3 points: equilateral triangle in xy plane (iv) 4 points
176
* x,x,x, x,-x,-x, -x,x,-x, -x,-x,x (1a) 1 ligand(B) of refAtom which itself
177
* has a ligand (J) (i) 1 points required; vector along AB vector (ii) 2
178
* points: 2 vectors in ABJ plane, staggered and eclipsed wrt J (iii) 3
179
* points: 1 staggered wrt J, the others +- gauche wrt J (1b) 1 ligand(B) of
180
* refAtom which has no other ligands. A random J is generated and (1a)
181
* applied (2) 2 ligands(B, C) of refAtom A (i) 1 points required; vector in
182
* ABC plane bisecting AB, AC. If ABC is linear, no points (ii) 2 points: 2
183
* vectors at angle ang, whose resultant is 2i (3) 3 ligands(B, C, D) of
184
* refAtom A (i) 1 points required; if A, B, C, D coplanar, no points. else
185
* vector is resultant of BA, CA, DA fails if atom itself has no coordinates
188
*@param refAtom (A) to which new ligands coordinates could be added
189
*@param length A-X length
190
*@param angle B-A-X angle (used in certain cases)
191
*@param nwanted Description of the Parameter
192
*@param noCoords Description of the Parameter
193
*@param withCoords Description of the Parameter
194
*@param atomC Description of the Parameter
195
*@return Point3D[] points calculated. If request could not be
196
* fulfilled (e.g. too many atoms, or strange geometry, returns empty
197
* array (zero length, not null)
198
*@exception Exception Description of the Exception
199
*@cdk.keyword coordinate generation
202
public Point3d[] get3DCoordinatesForLigands(IAtom refAtom,
203
IAtomContainer noCoords, IAtomContainer withCoords, IAtom atomC, int nwanted, double length, double angle) throws Exception {
204
Point3d newPoints[] = new Point3d[1];
206
if (noCoords.getAtomCount() == 0 && withCoords.getAtomCount() == 0) {
210
// too many ligands at present
211
if (withCoords.getAtomCount() > 3) {
215
if (refAtom.getFormalNeighbourCount() == 1 || refAtom.getMaxBondOrder() > 4) {
216
} else if (refAtom.getFormalNeighbourCount() == 2 || refAtom.getMaxBondOrder() == 3) {
221
newPoints[0] = get3DCoordinatesForSPLigands(refAtom, withCoords, length, angle);
222
} else if (refAtom.getFormalNeighbourCount() == 3 || (refAtom.getMaxBondOrder() > 1 && refAtom.getMaxBondOrder() < 3)) {
228
newPoints = get3DCoordinatesForSP2Ligands(refAtom, noCoords, withCoords, atomC, length, angle);
229
} catch (Exception ex1) {
230
// logger.debug("Get3DCoordinatesForLigandsERROR: Cannot place SP2 Ligands due to:" + ex1.toString());
231
throw new IOException("Cannot place sp2 substituents");
237
newPoints = get3DCoordinatesForSP3Ligands(refAtom, noCoords, withCoords, atomC, nwanted, length, angle);
238
} catch (Exception ex1) {
239
// logger.debug("Get3DCoordinatesForLigandsERROR: Cannot place SP3 Ligands due to:" + ex1.toString());
240
throw new IOException("Cannot place sp3 substituents");
243
//logger.debug("...Ready "+newPoints.length+" "+newPoints[0].toString());
247
public Point3d get3DCoordinatesForSPLigands(IAtom refAtom, IAtomContainer withCoords, double length, double angle) {
248
//logger.debug(" SP Ligands start "+refAtom.getPoint3d()+" "+(withCoords.getAtomAt(0)).getPoint3d());
249
Vector3d ca = new Vector3d(refAtom.getPoint3d());
250
ca.sub((withCoords.getAtom(0)).getPoint3d());
253
Point3d newPoint = new Point3d(refAtom.getPoint3d());
260
* Main method for the calculation of the ligand coordinates for sp2 atoms.
261
* Decides if one or two coordinates should be created
263
*@param refAtom central atom (Atom)
264
*@param noCoords Description of the Parameter
265
*@param withCoords Description of the Parameter
266
*@param atomC Description of the Parameter
267
*@param length Description of the Parameter
268
*@param angle Description of the Parameter
269
*@return coordinates as Points3d []
271
public Point3d[] get3DCoordinatesForSP2Ligands(IAtom refAtom, IAtomContainer noCoords, IAtomContainer withCoords, IAtom atomC, double length, double angle) {
272
//logger.debug(" SP2 Ligands start");
273
Point3d newPoints[] = new Point3d[1];
277
if (withCoords.getAtomCount() >= 2) {
278
//logger.debug("Wanted:1 "+noCoords.getAtomCount());
279
newPoints[0] = calculate3DCoordinatesSP2_1(refAtom.getPoint3d(), (withCoords.getAtom(0)).getPoint3d(),
280
(withCoords.getAtom(1)).getPoint3d(), length, -1 * angle);
282
} else if (withCoords.getAtomCount() <= 1) {
283
//logger.debug("NoCoords 2:"+noCoords.getAtomCount());
284
newPoints = calculate3DCoordinatesSP2_2(refAtom.getPoint3d(), (withCoords.getAtom(0)).getPoint3d(),
285
(atomC != null) ? atomC.getPoint3d() : null, length, angle);
287
//logger.debug("Ready SP2");
293
* Main method for the calculation of the ligand coordinates for sp3 atoms.
294
* Decides how many coordinates should be created
296
*@param refAtom central atom (Atom)
297
*@param nwanted how many ligands should be created
298
*@param length bond length
299
*@param angle angle in a B-A-(X) system; a=central atom;
300
* x=ligand with unknown coordinates
301
*@param noCoords Description of the Parameter
302
*@param withCoords Description of the Parameter
303
*@param atomC Description of the Parameter
304
*@return Description of the Return Value
306
public Point3d[] get3DCoordinatesForSP3Ligands(IAtom refAtom, IAtomContainer noCoords, IAtomContainer withCoords, IAtom atomC, int nwanted, double length, double angle) {
307
//logger.debug("SP3 Ligands start ");
308
Point3d newPoints[] = new Point3d[0];
309
Point3d aPoint = refAtom.getPoint3d();
310
int nwithCoords = withCoords.getAtomCount();
312
angle = TETRAHEDRAL_ANGLE;
314
if (nwithCoords == 0) {
315
newPoints = calculate3DCoordinates0(refAtom.getPoint3d(), nwanted, length);
316
} else if (nwithCoords == 1) {
317
newPoints = calculate3DCoordinates1(aPoint, (withCoords.getAtom(0)).getPoint3d(), (atomC != null) ? atomC.getPoint3d() : null, nwanted, length, angle);
318
} else if (nwithCoords == 2) {
319
Point3d bPoint = withCoords.getAtom(0).getPoint3d();
320
Point3d cPoint = withCoords.getAtom(1).getPoint3d();
321
newPoints = calculate3DCoordinates2(aPoint, bPoint, cPoint, nwanted, length, angle);
322
} else if (nwithCoords == 3) {
323
Point3d bPoint = withCoords.getAtom(0).getPoint3d();
324
Point3d cPoint = withCoords.getAtom(1).getPoint3d();
325
newPoints = new Point3d[1];
326
Point3d dPoint = withCoords.getAtom(2).getPoint3d();
327
newPoints[0] = calculate3DCoordinates3(aPoint, bPoint, cPoint, dPoint, length);
329
//logger.debug("...Ready");
335
* Calculates substituent points. Calculate substituent points for (0) zero
336
* ligands of aPoint. The resultant points are randomly oriented: (i) 1 points
337
* required; +x,0,0 (ii) 2 points: use +x,0,0 and -x,0,0 (iii) 3 points:
338
* equilateral triangle in xy plane (iv) 4 points x,x,x, x,-x,-x, -x,x,-x,
339
* -x,-x,x where 3x**2 = bond length
341
*@param aPoint to which substituents are added
342
*@param nwanted number of points to calculate (1-4)
343
*@param length from aPoint
344
*@return Point3d[] nwanted points (or zero if failed)
346
public Point3d[] calculate3DCoordinates0(Point3d aPoint, int nwanted, double length) {
347
Point3d points[] = new Point3d[0];
349
points = new Point3d[1];
350
points[0] = new Point3d(aPoint);
351
points[0].add(new Vector3d(length, 0.0, 0.0));
352
} else if (nwanted == 2) {
353
points[0] = new Point3d(aPoint);
354
points[0].add(new Vector3d(length, 0.0, 0.0));
355
points[1] = new Point3d(aPoint);
356
points[1].add(new Vector3d(-length, 0.0, 0.0));
357
} else if (nwanted == 3) {
358
points[0] = new Point3d(aPoint);
359
points[0].add(new Vector3d(length, 0.0, 0.0));
360
points[1] = new Point3d(aPoint);
361
points[1].add(new Vector3d(-length * 0.5, -length * 0.5 * Math.sqrt(3.0), 0.0f));
362
points[2] = new Point3d(aPoint);
363
points[2].add(new Vector3d(-length * 0.5, length * 0.5 * Math.sqrt(3.0), 0.0f));
364
} else if (nwanted == 4) {
365
double dx = length / Math.sqrt(3.0);
366
points[0] = new Point3d(aPoint);
367
points[0].add(new Vector3d(dx, dx, dx));
368
points[1] = new Point3d(aPoint);
369
points[1].add(new Vector3d(dx, -dx, -dx));
370
points[2] = new Point3d(aPoint);
371
points[2].add(new Vector3d(-dx, -dx, dx));
372
points[3] = new Point3d(aPoint);
373
points[3].add(new Vector3d(-dx, dx, -dx));
380
* Calculate new point(s) X in a B-A system to form B-A-X. Use C as reference
381
* for * staggering about the B-A bond (1a) 1 ligand(B) of refAtom (A) which
382
* itself has a ligand (C) (i) 1 points required; vector along AB vector (ii)
383
* 2 points: 2 vectors in ABC plane, staggered and eclipsed wrt C (iii) 3
384
* points: 1 staggered wrt C, the others +- gauche wrt C If C is null, a
385
* random non-colinear C is generated
387
*@param aPoint to which substituents are added
388
*@param nwanted number of points to calculate (1-3)
389
*@param length A-X length
390
*@param angle B-A-X angle
391
*@param bPoint Description of the Parameter
392
*@param cPoint Description of the Parameter
393
*@return Point3d[] nwanted points (or zero if failed)
395
public Point3d[] calculate3DCoordinates1(
396
Point3d aPoint, Point3d bPoint, Point3d cPoint,
397
int nwanted, double length, double angle
399
Point3d points[] = new Point3d[nwanted];
401
Vector3d ba = new Vector3d(aPoint);
404
// if no cPoint, generate a random reference
405
if (cPoint == null) {
406
Vector3d cVector = getNonColinearVector(ba);
407
cPoint = new Point3d(cVector);
410
Vector3d cb = new Vector3d(bPoint);
413
// if A, B, C colinear, replace C by random point
414
double cbdotba = cb.dot(ba);
415
if (cbdotba > 0.999999) {
416
Vector3d cVector = getNonColinearVector(ba);
417
cPoint = new Point3d(cVector);
418
cb = new Vector3d(bPoint);
422
Vector3d cbxba = new Vector3d();
425
// create three perp axes ba, cbxba, and ax
426
Vector3d ax = new Vector3d();
429
double drot = Math.PI * 2.0 / (double) nwanted;
430
for (int i = 0; i < nwanted; i++) {
431
double rot = (double) i * drot;
432
points[i] = new Point3d(aPoint);
433
Vector3d vx = new Vector3d(ba);
434
vx.scale(-Math.cos(angle) * length);
435
Vector3d vy = new Vector3d(ax);
436
vy.scale(Math.cos(rot) * length);
437
Vector3d vz = new Vector3d(cbxba);
438
vz.scale(Math.sin(rot) * length);
452
* Calculate new point(s) X in a B-A-C system, it forms a B-A(-C)-X
453
* system. (2) 2 ligands(B, C) of refAtom A (i) 1 points required; vector in
454
* ABC plane bisecting AB, AC. If ABC is linear, no points (ii) 2 points: 2
455
* points X1, X2, X1-A-X2 = angle about 2i vector
457
*@param aPoint to which substituents are added
458
*@param bPoint first ligand of A
459
*@param cPoint second ligand of A
460
*@param nwanted number of points to calculate (1-2)
461
*@param length A-X length
462
*@param angle B-A-X angle
463
*@return Point3d[] nwanted points (or zero if failed)
465
public Point3d[] calculate3DCoordinates2(
466
Point3d aPoint, Point3d bPoint, Point3d cPoint,
467
int nwanted, double length, double angle) {
468
//logger.debug("3DCoordinates2");
469
Point3d newPoints[] = new Point3d[0];
470
double ang2 = angle / 2.0;
472
Vector3d ba = new Vector3d(aPoint);
474
Vector3d ca = new Vector3d(aPoint);
476
Vector3d baxca = new Vector3d();
478
if (baxca.length() < 0.00000001) {
481
} else if (nwanted == 1) {
482
newPoints = new Point3d[1];
483
Vector3d ax = new Vector3d(ba);
487
newPoints[0] = new Point3d(aPoint);
488
newPoints[0].add(ax);
489
} else if (nwanted >= 2) {
490
newPoints = new Point3d[2];
491
Vector3d ax = new Vector3d(ba);
495
baxca.scale(Math.sin(ang2) * length);
496
ax.scale(Math.cos(ang2) * length);
497
newPoints[0] = new Point3d(aPoint);
498
newPoints[0].add(ax);
499
newPoints[0].add(baxca);
500
newPoints[1] = new Point3d(aPoint);
501
newPoints[1].add(ax);
502
newPoints[1].sub(baxca);
512
* Calculate new point X in a B-A(-D)-C system. It forms a B-A(-D)(-C)-X
513
* system. (3) 3 ligands(B, C, D) of refAtom A (i) 1 points required; if A, B,
514
* C, D coplanar, no points. else vector is resultant of BA, CA, DA
516
*@param aPoint to which substituents are added
517
*@param bPoint first ligand of A
518
*@param cPoint second ligand of A
519
*@param dPoint third ligand of A
520
*@param length A-X length
521
*@return Point3d nwanted points (or null if failed (coplanar))
523
public Point3d calculate3DCoordinates3(
524
Point3d aPoint, Point3d bPoint, Point3d cPoint, Point3d dPoint,
526
//logger.debug("3DCoordinates3");
527
Vector3d bc = new Vector3d(bPoint);
529
Vector3d dc = new Vector3d(dPoint);
531
Vector3d ca = new Vector3d(cPoint);
534
Vector3d n1 = new Vector3d();
535
Vector3d n2 = new Vector3d();
541
Vector3d ax = new Vector3d(aPoint);
545
Vector3d ax2 = new Vector3d(aPoint);
549
Point3d point = new Point3d(aPoint);
551
double dotProduct = ca.dot(ax);
552
double angle = Math.acos((dotProduct) / (ax.length() * ca.length()));
573
* Calculate new point in B-A-C system. It forms B-A(-X)-C system, where A is
576
*@param aPoint central point A (Point3d)
577
*@param bPoint B (Point3d)
578
*@param cPoint C (Point3d)
579
*@param length bond length
580
*@param angle angle between B(C)-A-X
581
*@return new Point (Point3d)
583
public Point3d calculate3DCoordinatesSP2_1(Point3d aPoint, Point3d bPoint, Point3d cPoint,
584
double length, double angle) {
585
//logger.debug("3DCoordinatesSP2_1");
586
Vector3d ba = new Vector3d(bPoint);
588
Vector3d ca = new Vector3d(cPoint);
591
Vector3d n1 = new Vector3d();
595
Vector3d n2 = rotate(ba, n1, angle);
599
Point3d point = new Point3d(aPoint);
610
* Calculate two new points in B-A system. It forms B-A(-X)(-X) system, where
613
*@param aPoint central point A (Point3d)
614
*@param bPoint B (Point3d)
615
*@param cPoint C (Point3d)
616
*@param length bond length
617
*@param angle angle between B(C)-A-X
618
*@return new Points (Point3d [])
620
public Point3d[] calculate3DCoordinatesSP2_2(Point3d aPoint, Point3d bPoint, Point3d cPoint, double length, double angle) {
621
//logger.debug("3DCoordinatesSP_2");
622
Vector3d ca = new Vector3d();
623
Point3d newPoints[] = new Point3d[2];
624
Vector3d ba = new Vector3d(bPoint);
627
if (cPoint != null) {
628
ca.x = cPoint.x - aPoint.x;
629
ca.y = cPoint.y - aPoint.y;
630
ca.z = cPoint.z - aPoint.z;
637
Vector3d crossProduct = new Vector3d();
638
crossProduct.cross(ba, ca);
640
Vector3d n1 = rotate(ba, crossProduct, 2 * angle);
643
newPoints[0] = new Point3d(aPoint);
644
newPoints[0].add(n1);
646
Vector3d n2 = rotate(n1, ba, Math.PI);
649
newPoints[1] = new Point3d(aPoint);
650
newPoints[1].add(n2);
660
* Gets the nonColinearVector attribute of the AtomLigandPlacer3D class
662
*@param ab Description of the Parameter
663
*@return The nonColinearVector value
665
private Vector3d getNonColinearVector(Vector3d ab) {
666
Vector3d cr = new Vector3d();
668
if (cr.length() > 0.00001) {
677
* Rotates a vector around an axis
679
*@param vector vector to be rotated around axis
680
*@param axis axis of rotation
681
*@param angle angle to vector rotate around
682
*@return rotated vector
685
public static Vector3d rotate(Vector3d vector, Vector3d axis, double angle) {
686
Matrix3d rotate = new Matrix3d();
687
rotate.set(new AxisAngle4d(axis.x, axis.y, axis.z, angle));
688
Vector3d result = new Vector3d();
689
rotate.transform(vector, result);
695
* Gets the distance between two atoms out of the parameter set.
697
*@param id1 id of the paramter set for atom1 (atom1.getAtomTypeName())
698
*@param id2 id of the paramter set for atom2
699
*@return The distanceValue value
700
*@exception Exception Description of the Exception
702
private double getDistanceValue(String id1, String id2) throws Exception {
704
if (pSet.containsKey(("bond" + id1 + ";" + id2))) {
705
dkey = "bond" + id1 + ";" + id2;
706
} else if (pSet.containsKey(("bond" + id2 + ";" + id1))) {
707
dkey = "bond" + id2 + ";" + id1;
709
// logger.debug("DistanceKEYError:pSet has no key:" + id2 + " ; " + id1 + " take default bond length:" + DEFAULT_BOND_LENGTH_H);
710
return DEFAULT_BOND_LENGTH_H;
712
return ((Double) (((Vector) pSet.get(dkey)).get(0))).doubleValue();
717
* Gets the angleKey attribute of the AtomPlacer3D object
719
*@param id1 Description of the Parameter
720
*@param id2 Description of the Parameter
721
*@param id3 Description of the Parameter
722
*@return The angleKey value
723
*@exception Exception Description of the Exception
725
public double getAngleValue(String id1, String id2, String id3) throws Exception {
727
if (pSet.containsKey(("angle" + id1 + ";" + id2 + ";" + id3))) {
728
akey = "angle" + id1 + ";" + id2 + ";" + id3;
729
} else if (pSet.containsKey(("angle" + id3 + ";" + id2 + ";" + id1))) {
730
akey = "angle" + id3 + ";" + id2 + ";" + id1;
731
} else if (pSet.containsKey(("angle" + id2 + ";" + id1 + ";" + id3))) {
732
akey = "angle" + id2 + ";" + id1 + ";" + id3;
733
} else if (pSet.containsKey(("angle" + id1 + ";" + id3 + ";" + id2))) {
734
akey = "angle" + id1 + ";" + id3 + ";" + id2;
735
} else if (pSet.containsKey(("angle" + id3 + ";" + id1 + ";" + id2))) {
736
akey = "angle" + id3 + ";" + id1 + ";" + id2;
737
} else if (pSet.containsKey(("angle" + id2 + ";" + id3 + ";" + id1))) {
738
akey = "angle" + id2 + ";" + id3 + ";" + id1;
740
System.out.println("AngleKEYError:Unknown angle " + id1 + " " + id2 + " " + id3 + " take default angle:" + TETRAHEDRAL_ANGLE);
741
return TETRAHEDRAL_ANGLE;
743
return ((Double) (((Vector) pSet.get(akey)).get(0))).doubleValue();
748
* set Atoms in respect to stereoinformation.
749
* take placed neighbours to stereocenter
751
* if right handed system (spatproduct >0)
752
* if unplaced is not up (relativ to stereocenter)
754
* Determine angle between n and possible ligand place points
755
* if angle smaller than 90 degrees take this branch point
757
*@param atomA placed Atom - stereocenter
758
*@param ax bond between stereocenter and unplaced atom
759
*@param atomB neighbour of atomA (in plane created by atomA, atomB and atomC)
760
*@param atomC neighbour of atomA
761
*@param branchPoints the two possible placement points for unplaced atom (up and down)
762
*@return int value of branch point position
764
public int makeStereocenter(Point3d atomA, IBond ax, Point3d atomB, Point3d atomC, Point3d[] branchPoints) {
766
Vector3d b = new Vector3d((atomB.x - atomA.x), (atomB.y - atomA.y), (atomB.z - atomA.z));
767
Vector3d c = new Vector3d((atomC.x - atomA.x), (atomC.y - atomA.y), (atomC.z - atomA.z));
768
Vector3d n1 = new Vector3d();
773
if (getSpatproduct(b, c, n1) >= 0) {
774
if (ax.getStereo() != CDKConstants.STEREO_BOND_UP_INV) {
779
double dotProduct = 0;
780
for (int i = 0; i < branchPoints.length; i++) {
781
n2 = new Vector3d(branchPoints[0].x, branchPoints[0].y, branchPoints[0].z);
782
dotProduct = n1.dot(n2);
783
if (Math.acos(dotProduct / (n1.length() * n2.length())) < 1.6) {
792
* Gets the spatproduct of three vectors
797
*@return double value of the spatproduct
799
public double getSpatproduct(Vector3d a, Vector3d b, Vector3d c) {
800
return (c.x * (b.y * a.z - b.z * a.y) + c.y * (b.z * a.x - b.x * a.z) + c.z * (b.x * a.y - b.y * a.x));
805
* Calculates the torsionAngle of a-b-c-d
811
*@return The torsionAngle value
813
public double getTorsionAngle(Point3d a, Point3d b, Point3d c, Point3d d) {
814
Vector3d ab = new Vector3d(a.x - b.x, a.y - b.y, a.z - b.z);
815
Vector3d cb = new Vector3d(c.x - b.x, c.y - b.y, c.z - b.z);
816
Vector3d dc = new Vector3d(d.x - c.x, d.y - c.y, d.z - c.z);
817
Vector3d bc = new Vector3d(b.x - c.x, b.y - c.y, b.z - c.z);
818
Vector3d n1 = new Vector3d();
819
Vector3d n2 = new Vector3d();
822
if (getSpatproduct(ab, cb, n1) > 0) {
827
if (getSpatproduct(dc, bc, n2) < 0) {
836
* Gets all placed neighbouring atoms of a atom
838
*@param atom central atom (Atom)
839
*@param ac the molecul
840
*@return all connected and placed atoms to the central atom
843
public IAtomContainer getPlacedAtomsInAtomContainer(IAtom atom, IAtomContainer ac) {
845
java.util.List bonds = ac.getConnectedBondsList(atom);
846
IAtomContainer connectedAtoms = new org.openscience.cdk.AtomContainer();
847
IAtom connectedAtom = null;
848
for (int i = 0; i < bonds.size(); i++) {
849
connectedAtom = ((IBond)bonds.get(i)).getConnectedAtom(atom);
850
if (connectedAtom.getFlag(CDKConstants.ISPLACED)) {
851
connectedAtoms.addAtom(connectedAtom);
854
return connectedAtoms;
859
* Gets the unsetAtomsInAtomContainer attribute of the
860
* AtomTetrahedralLigandPlacer3D object
862
*@param atom Description of the Parameter
863
*@param ac Description of the Parameter
864
*@return The unsetAtomsInAtomContainer value
866
public IAtomContainer getUnsetAtomsInAtomContainer(IAtom atom, IAtomContainer ac) {
867
java.util.List atoms = ac.getConnectedAtomsList(atom);
868
IAtomContainer connectedAtoms = new org.openscience.cdk.AtomContainer();
869
for (int i = 0; i < atoms.size(); i++) {
870
IAtom curAtom = (IAtom)atoms.get(i);
871
if (!curAtom.getFlag(CDKConstants.ISPLACED)){//&& atoms[i].getPoint3d() == null) {
872
connectedAtoms.addAtom(curAtom);
875
return connectedAtoms;
878
public boolean hasUnsetNeighbour(IAtom atom, IAtomContainer ac) {
879
java.util.List atoms = ac.getConnectedAtomsList(atom);
880
for (int i = 0; i < atoms.size(); i++) {
881
IAtom curAtom = (IAtom)atoms.get(i);
882
if (!curAtom.getFlag(CDKConstants.ISPLACED)) {//&& atoms[i].getPoint3d() == null) {
891
* Returns a placed neighbouring atom of a central atom atomA, which is not
894
*@param atomA central atom (Atom)
895
*@param atomB atom connected to atomA (Atom)
897
*@return returns a connected atom (Atom)
899
public IAtom getPlacedHeavyAtomInAtomContainer(IAtom atomA, IAtom atomB, IAtomContainer ac) {
900
java.util.List atoms = ac.getConnectedAtomsList(atomA);
902
for (int i = 0; i < atoms.size(); i++) {
903
IAtom curAtom = (IAtom)atoms.get(i);
904
if (curAtom.getFlag(CDKConstants.ISPLACED) && !curAtom.getSymbol().equals("H")
905
&& curAtom != atomB) {