/// <summary> /// Takes the given Z Matrix coordinates and converts them to cartesian coordinates. /// The first Atom end up in the origin, the second on on the x axis, and the third /// one in the XY plane. The rest is added by applying the Zmatrix distances, angles /// and dihedrals. Assign coordinates directly to the atoms. /// </summary> /// <param name="molecule">the molecule to be placed in 3D</param> /// <param name="flagBranched">marks branched chain</param> // @author: egonw,cho public virtual void ZMatrixChainToCartesian(IAtomContainer molecule, bool flagBranched) { Vector3?result = null; for (int index = 0; index < distances.Length; index++) { if (index == 0) { result = new Vector3(0d, 0d, 0d); } else if (index == 1) { result = new Vector3(distances[1], 0d, 0d); } else if (index == 2) { result = new Vector3(-Math.Cos((angles[2] / 180) * Math.PI) * distances[2] + distances[1], Math.Sin((angles[2] / 180) * Math.PI) * distances[2], 0); } else { var cd = molecule.Atoms[thirdAtoms[index]].Point3D.Value - molecule.Atoms[secondAtoms[index]].Point3D.Value; var bc = molecule.Atoms[secondAtoms[index]].Point3D.Value - molecule.Atoms[firstAtoms[index - 3]].Point3D.Value; var n1 = Vector3.Cross(cd, bc); n1 = Vector3.Normalize(n1); Vector3 n2; if (index == 3 && flagBranched) { n2 = AtomTetrahedralLigandPlacer3D.Rotate(n1, bc, DIHEDRAL_BRANCHED_CHAIN); } else { n2 = AtomTetrahedralLigandPlacer3D.Rotate(n1, bc, dihedrals[index]); } n2 = Vector3.Normalize(n2); Vector3 ba = new Vector3(); if (index == 3 && flagBranched) { ba = AtomTetrahedralLigandPlacer3D.Rotate(cd, n2, (-angles[index] / 180) * Math.PI); ba = AtomTetrahedralLigandPlacer3D.Rotate(ba, cd, (-angles[index] / 180) * Math.PI); } else { ba = AtomTetrahedralLigandPlacer3D.Rotate(cd, n2, (-angles[index] / 180) * Math.PI); } ba = Vector3.Normalize(ba); Vector3 ban = ba; ban *= distances[index]; result = molecule.Atoms[firstAtoms[index - 1]].Point3D.Value + ban; } IAtom atom = molecule.Atoms[firstAtoms[index]]; if ((atom.Point3D == null || !atom.IsPlaced) && !atom.IsInRing && IsHeavyAtom(atom)) { atom.Point3D = result; atom.IsPlaced = true; } } }
/// <summary> /// Layout the ring system, rotate and translate the template. /// </summary> /// <param name="originalCoord">coordinates of the placedRingAtom from the template</param> /// <param name="placedRingAtom">placedRingAtom</param> /// <param name="ringSet">ring system which placedRingAtom is part of</param> /// <param name="centerPlacedMolecule">the geometric center of the already placed molecule</param> /// <param name="atomB">placed neighbour atom of placedRingAtom</param> private static void LayoutRingSystem(Vector3 originalCoord, IAtom placedRingAtom, IRingSet ringSet, Vector3 centerPlacedMolecule, IAtom atomB, AtomPlacer3D ap3d) { //Debug.WriteLine("****** Layout ring System ******");Console.Out.WriteLine(">around atom:"+molecule.Atoms.IndexOf(placedRingAtom)); IAtomContainer ac = RingSetManipulator.GetAllInOneContainer(ringSet); Vector3 newCoord = placedRingAtom.Point3D.Value; Vector3 axis = new Vector3(atomB.Point3D.Value.X - newCoord.X, atomB.Point3D.Value.Y - newCoord.Y, atomB.Point3D.Value.Z - newCoord.Z); TranslateStructure(originalCoord, newCoord, ac); //Rotate Ringsystem to farthest possible point Vector3 startAtomVector = new Vector3(newCoord.X - atomB.Point3D.Value.X, newCoord.Y - atomB.Point3D.Value.Y, newCoord.Z - atomB.Point3D.Value.Z); IAtom farthestAtom = ap3d.GetFarthestAtom(placedRingAtom.Point3D.Value, ac); Vector3 farthestAtomVector = new Vector3(farthestAtom.Point3D.Value.X - newCoord.X, farthestAtom.Point3D.Value.Y - newCoord.Y, farthestAtom.Point3D.Value.Z - newCoord.Z); Vector3 n1 = Vector3.Cross(axis, farthestAtomVector); n1 = Vector3.Normalize(n1); double lengthFarthestAtomVector = farthestAtomVector.Length(); Vector3 farthestVector = startAtomVector; farthestVector = Vector3.Normalize(farthestVector); farthestVector *= startAtomVector.Length() + lengthFarthestAtomVector; double dotProduct = Vector3.Dot(farthestAtomVector, farthestVector); double angle = Math.Acos(dotProduct / (farthestAtomVector.Length() * farthestVector.Length())); Vector3 ringCenter = new Vector3(); for (int i = 0; i < ac.Atoms.Count; i++) { if (!(ac.Atoms[i].IsPlaced)) { ringCenter.X = (ac.Atoms[i].Point3D).Value.X - newCoord.X; ringCenter.Y = (ac.Atoms[i].Point3D).Value.Y - newCoord.Y; ringCenter.Z = (ac.Atoms[i].Point3D).Value.Z - newCoord.Z; ringCenter = AtomTetrahedralLigandPlacer3D.Rotate(ringCenter, n1, angle); ac.Atoms[i].Point3D = new Vector3(ringCenter.X + newCoord.X, ringCenter.Y + newCoord.Y, ringCenter.Z + newCoord.Z); //ac.GetAtomAt(i).IsPlaced = true; } } //Rotate Ring so that geometric center is max from placed center //Debug.WriteLine("Rotate RINGSYSTEM"); Vector3 pointRingCenter = GeometryUtil.Get3DCenter(ac); double distance = 0; double rotAngleMax = 0; angle = 1 / 180 * Math.PI; ringCenter = new Vector3(pointRingCenter.X, pointRingCenter.Y, pointRingCenter.Z); ringCenter.X = ringCenter.X - newCoord.X; ringCenter.Y = ringCenter.Y - newCoord.Y; ringCenter.Z = ringCenter.Z - newCoord.Z; for (int i = 1; i < 360; i++) { ringCenter = AtomTetrahedralLigandPlacer3D.Rotate(ringCenter, axis, angle); if (Vector3.Distance(centerPlacedMolecule, new Vector3(ringCenter.X, ringCenter.Y, ringCenter.Z)) > distance) { rotAngleMax = i; distance = Vector3.Distance(centerPlacedMolecule, new Vector3(ringCenter.X, ringCenter.Y, ringCenter.Z)); } } //rotate ring around axis with best angle rotAngleMax = (rotAngleMax / 180) * Math.PI; for (int i = 0; i < ac.Atoms.Count; i++) { if (!(ac.Atoms[i].IsPlaced)) { ringCenter.X = (ac.Atoms[i].Point3D).Value.X; ringCenter.Y = (ac.Atoms[i].Point3D).Value.Y; ringCenter.Z = (ac.Atoms[i].Point3D).Value.Z; ringCenter = AtomTetrahedralLigandPlacer3D.Rotate(ringCenter, axis, rotAngleMax); ac.Atoms[i].Point3D = new Vector3(ringCenter.X, ringCenter.Y, ringCenter.Z); ac.Atoms[i].IsPlaced = true; } } }