Example #1
0
        /// <summary>
        /// Layout all rings in the given RingSet that are connected to a given Ring
        /// </summary>
        /// <param name="rs">The RingSet to be searched for rings connected to Ring</param>
        /// <param name="ring">The Ring for which all connected rings in RingSet are to be layed out.</param>
        public void PlaceConnectedRings(IRingSet rs, IRing ring, int handleType, double bondLength)
        {
            var connectedRings = rs.GetConnectedRings(ring);

            //        Debug.WriteLine(rs.ReportRingList(Molecule));
            foreach (var container in connectedRings)
            {
                IRing connectedRing = (IRing)container;
                if (!connectedRing.IsPlaced)
                {
                    //                Debug.WriteLine(ring.ToString(Molecule));
                    //                Debug.WriteLine(connectedRing.ToString(Molecule));
                    IAtomContainer sharedAtoms    = AtomContainerManipulator.GetIntersection(ring, connectedRing);
                    int            numSharedAtoms = sharedAtoms.Atoms.Count;
                    Debug.WriteLine("placeConnectedRings-> connectedRing: " + (ring.ToString()));
                    if ((numSharedAtoms == 2 && handleType == Fused) ||
                        (numSharedAtoms == 1 && handleType == Spiro) ||
                        (numSharedAtoms > 2 && handleType == Bridged))
                    {
                        Vector2 sharedAtomsCenter   = GeometryUtil.Get2DCenter(sharedAtoms);
                        Vector2 oldRingCenter       = GeometryUtil.Get2DCenter(ring);
                        Vector2 tempVector          = sharedAtomsCenter;
                        Vector2 newRingCenterVector = tempVector;
                        newRingCenterVector -= oldRingCenter;

                        // zero (or v. small ring center)
                        if (Math.Abs(newRingCenterVector.X) < 0.001 && Math.Abs(newRingCenterVector.Y) < 0.001)
                        {
                            // first see if we can use terminal bonds
                            IAtomContainer terminalOnly = Molecule.Builder.NewAtomContainer();

                            foreach (IAtom atom in ring.Atoms)
                            {
                                if (ring.GetConnectedBonds(atom).Count() == 1)
                                {
                                    terminalOnly.Atoms.Add(atom);
                                }
                            }

                            if (terminalOnly.Atoms.Count == 2)
                            {
                                newRingCenterVector = GeometryUtil.Get2DCenter(terminalOnly);
                                newRingCenterVector = oldRingCenter;
                                connectedRing.SetProperty(RingPlacer.SnapHint, true);
                            }
                            else
                            {
                                // project coordinates on 12 axis (30 degree snaps) and choose one with most spread
                                Vector2 vec     = new Vector2(0, 1);
                                double  bestLen = -double.MaxValue;

                                for (int i = 0; i < 12; i++)
                                {
                                    Vector2 orth = new Vector2(-vec.Y, vec.X);
                                    orth = Vector2.Normalize(orth);
                                    double min = double.MaxValue, max = -double.MaxValue;
                                    foreach (IAtom atom in sharedAtoms.Atoms)
                                    {
                                        // s: scalar projection
                                        double s = Vector2.Dot(orth, atom.Point2D.Value);
                                        if (s < min)
                                        {
                                            min = s;
                                        }
                                        if (s > max)
                                        {
                                            max = s;
                                        }
                                    }
                                    double len = max - min;
                                    if (len > bestLen)
                                    {
                                        bestLen             = len;
                                        newRingCenterVector = vec;
                                    }
                                    Rotate(vec, RAD_30);
                                }
                            }
                        }

                        Vector2 oldRingCenterVector = newRingCenterVector;
                        Debug.WriteLine($"placeConnectedRing -> tempVector: {tempVector}, tempVector.Length: {tempVector.Length()}");
                        Debug.WriteLine($"placeConnectedRing -> bondCenter: {sharedAtomsCenter}");
                        Debug.WriteLine($"placeConnectedRing -> oldRingCenterVector.Length: {oldRingCenterVector.Length()}");
                        Debug.WriteLine($"placeConnectedRing -> newRingCenterVector.Length: {newRingCenterVector.Length()}");
                        Vector2 tempPoint = sharedAtomsCenter;
                        tempPoint += newRingCenterVector;
                        PlaceRing(connectedRing, sharedAtoms, sharedAtomsCenter, newRingCenterVector, bondLength);
                        connectedRing.IsPlaced = true;
                        PlaceConnectedRings(rs, connectedRing, handleType, bondLength);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Select the best scoring template + offset for the given macrocycle.
        /// </summary>
        /// <param name="macrocycle">macrocycle</param>
        /// <param name="ringset">entire ring system</param>
        /// <param name="wind">winding of ring CW/CCW</param>
        /// <param name="winding">winding of each turn in the ring</param>
        /// <returns>the best scoring configuration</returns>
        private static MacroScore BestScore(IRing macrocycle, IRingSet ringset, int wind, int[] winding)
        {
            var numAtoms = macrocycle.Atoms.Count;

            var heteroIdxs  = new List <int>();
            var ringAttachs = new List <IList <int> >();

            // hetero atoms
            for (int i = 0; i < numAtoms; i++)
            {
                if (macrocycle.Atoms[i].AtomicNumber != 6)
                {
                    heteroIdxs.Add(i);
                }
            }
            foreach (var other in ringset)
            {
                if (other == macrocycle)
                {
                    continue;
                }
                var shared = AtomContainerManipulator.GetIntersection(macrocycle, other);

                if (shared.Atoms.Count >= 2 && shared.Atoms.Count <= 4)
                {
                    ringAttachs.Add(GetAttachedInOrder(macrocycle, shared));
                }
            }

            // convex and concave are relative
            var convex  = wind;
            var concave = -wind;

            MacroScore best = null;

            for (int i = 0; i < winding.Length; i++)
            {
                // score ring attachs
                int nRingClick = 0;
                foreach (var ringAttach in ringAttachs)
                {
                    int r1, r2, r3, r4;
                    switch (ringAttach.Count)
                    {
                    case 2:
                        r1 = (ringAttach[0] + i) % numAtoms;
                        r2 = (ringAttach[1] + i) % numAtoms;
                        if (winding[r1] == winding[r2])
                        {
                            if (winding[r1] == convex)
                            {
                                nRingClick += 5;
                            }
                            else
                            {
                                nRingClick++;
                            }
                        }
                        break;

                    case 3:
                        r1 = (ringAttach[0] + i) % numAtoms;
                        r2 = (ringAttach[1] + i) % numAtoms;
                        r3 = (ringAttach[2] + i) % numAtoms;
                        if (winding[r1] == convex &&
                            winding[r2] == concave &&
                            winding[r3] == convex)
                        {
                            nRingClick += 5;
                        }
                        else if (winding[r1] == concave &&
                                 winding[r2] == convex &&
                                 winding[r3] == concave)
                        {
                            nRingClick++;
                        }
                        break;

                    case 4:
                        r1 = (ringAttach[0] + i) % numAtoms;
                        r2 = (ringAttach[1] + i) % numAtoms;
                        r3 = (ringAttach[2] + i) % numAtoms;
                        r4 = (ringAttach[3] + i) % numAtoms;
                        if (winding[r1] == convex &&
                            winding[r2] == concave &&
                            winding[r3] == concave &&
                            winding[r4] == convex)
                        {
                            nRingClick++;
                        }
                        else if (winding[r1] == concave &&
                                 winding[r2] == convex &&
                                 winding[r3] == convex &&
                                 winding[r4] == concave)
                        {
                            nRingClick++;
                        }
                        break;
                    }
                }

                // score hetero atoms in concave positions
                int nConcaveHetero = 0;
                foreach (var heteroIdx in heteroIdxs)
                {
                    var k = (heteroIdx + i) % numAtoms;
                    if (winding[k] == concave)
                    {
                        nConcaveHetero++;
                    }
                }

                int nCorrectStereo   = 0;
                int nIncorrectStereo = 0;
                foreach (var se in macrocycle.StereoElements)
                {
                    if (se.Class == StereoClass.CisTrans)
                    {
                        var bond = (IBond)se.Focus;
                        var beg  = bond.Begin;
                        var end  = bond.End;
                        StereoConfigurations cfg;
                        if (winding[(macrocycle.Atoms.IndexOf(beg) + i) % numAtoms] ==
                            winding[(macrocycle.Atoms.IndexOf(end) + i) % numAtoms])
                        {
                            cfg = StereoConfigurations.Together;
                        }
                        else
                        {
                            cfg = StereoConfigurations.Opposite;
                        }
                        if (cfg == se.Configure)
                        {
                            nCorrectStereo++;
                        }
                        else
                        {
                            nIncorrectStereo++;
                        }
                    }
                }

                var score = new MacroScore(i, nConcaveHetero, nCorrectStereo, nRingClick);
                if (score.CompareTo(best) < 0)
                {
                    best = score;
                }
            }

            return(best);
        }