public virtual void TestGetConnectedRings_IRing() { IRingSet ringset = (IRingSet)NewChemObject(); IAtom ring1Atom1 = ringset.Builder.NewAtom("C"); // rather artificial molecule IAtom ring1Atom2 = ringset.Builder.NewAtom("C"); IAtom sharedAtom1 = ringset.Builder.NewAtom("C"); IAtom sharedAtom2 = ringset.Builder.NewAtom("C"); IAtom ring2Atom1 = ringset.Builder.NewAtom("C"); IAtom ring2Atom2 = ringset.Builder.NewAtom("C"); IBond ring1Bond1 = ringset.Builder.NewBond(ring1Atom1, ring1Atom2); IBond ring1Bond2 = ringset.Builder.NewBond(sharedAtom1, ring1Atom1); IBond ring1Bond3 = ringset.Builder.NewBond(sharedAtom2, ring1Atom2); IBond sharedBond = ringset.Builder.NewBond(sharedAtom1, sharedAtom2); IBond ring2Bond1 = ringset.Builder.NewBond(ring2Atom1, ring2Atom2); IBond ring2Bond2 = ringset.Builder.NewBond(sharedAtom1, ring2Atom1); IBond ring2Bond3 = ringset.Builder.NewBond(sharedAtom2, ring2Atom2); IRing ring1 = ringset.Builder.NewRing(); ring1.Atoms.Add(ring1Atom1); ring1.Atoms.Add(ring1Atom2); ring1.Atoms.Add(sharedAtom1); ring1.Atoms.Add(sharedAtom2); ring1.Bonds.Add(ring1Bond1); ring1.Bonds.Add(ring1Bond2); ring1.Bonds.Add(ring1Bond3); ring1.Bonds.Add(sharedBond); IRing ring2 = ringset.Builder.NewRing(); ring2.Atoms.Add(ring2Atom1); ring2.Atoms.Add(ring2Atom2); ring2.Atoms.Add(sharedAtom1); ring2.Atoms.Add(sharedAtom2); ring2.Bonds.Add(ring2Bond1); ring2.Bonds.Add(ring2Bond2); ring2.Bonds.Add(ring2Bond3); ring2.Bonds.Add(sharedBond); ringset.Add(ring1); ringset.Add(ring2); Assert.AreEqual(1, ringset.GetConnectedRings(ring2).Count()); Assert.AreEqual(1, ringset.GetConnectedRings(ring1).Count()); }
/// <summary> /// Perform a walk in the given RingSet, starting at a given Ring and /// recursively searching for other Rings connected to this ring. By doing /// this it finds all rings in the RingSet connected to the start ring, /// putting them in newRs, and removing them from rs. /// </summary> /// <param name="rs">The RingSet to be searched</param> /// <param name="ring">The ring to start with</param> /// <param name="newRs">The RingSet containing all Rings connected to ring</param> /// <returns>newRs The RingSet containing all Rings connected to ring</returns> private static IRingSet WalkRingSystem(IRingSet rs, IRing ring, IRingSet newRs) { IRing tempRing; var tempRings = rs.GetConnectedRings(ring); rs.Remove(ring); foreach (var container in tempRings) { tempRing = (IRing)container; if (!newRs.Contains(tempRing)) { newRs.Add(tempRing); newRs.Add(WalkRingSystem(rs, tempRing, newRs)); } } return(newRs); }
/// <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); } } } }
public virtual void TestGetConnectedRingsBug1772613() { // Build a bridged and fused norbomane like ring system // C1CCC2C(C1)C4CC2C3CCCCC34 IRingSet ringSet = (IRingSet)NewChemObject(); IRing leftCyclohexane = ringSet.Builder.NewRing(6, "C"); IRing rightCyclopentane = ringSet.Builder.NewRing(5, "C"); IRing leftCyclopentane = ringSet.Builder.NewRing(); IBond leftCyclohexane0RightCyclopentane4 = ringSet.Builder.NewBond(leftCyclohexane.Atoms[0], rightCyclopentane.Atoms[4]); IBond leftCyclohexane1RightCyclopentane2 = ringSet.Builder.NewBond(leftCyclohexane.Atoms[1], rightCyclopentane.Atoms[2]); leftCyclopentane.Atoms.Add(leftCyclohexane.Atoms[0]); leftCyclopentane.Atoms.Add(leftCyclohexane.Atoms[1]); leftCyclopentane.Atoms.Add(rightCyclopentane.Atoms[2]); leftCyclopentane.Atoms.Add(rightCyclopentane.Atoms[3]); leftCyclopentane.Atoms.Add(rightCyclopentane.Atoms[4]); leftCyclopentane.Bonds.Add(leftCyclohexane.GetBond(leftCyclohexane.Atoms[0], leftCyclohexane.Atoms[1])); leftCyclopentane.Bonds.Add(leftCyclohexane1RightCyclopentane2); leftCyclopentane.Bonds.Add(rightCyclopentane.GetBond(rightCyclopentane.Atoms[2], rightCyclopentane.Atoms[3])); leftCyclopentane.Bonds.Add(rightCyclopentane.GetBond(rightCyclopentane.Atoms[3], rightCyclopentane.Atoms[4])); leftCyclopentane.Bonds.Add(leftCyclohexane0RightCyclopentane4); IRing rightCyclohexane = ringSet.Builder.NewRing(); IAtom rightCyclohexaneAtom0 = ringSet.Builder.NewAtom("C"); IAtom rightCyclohexaneAtom1 = ringSet.Builder.NewAtom("C"); IAtom rightCyclohexaneAtom2 = ringSet.Builder.NewAtom("C"); IAtom rightCyclohexaneAtom5 = ringSet.Builder.NewAtom("C"); IBond rightCyclohexaneAtom0Atom1 = ringSet.Builder.NewBond(rightCyclohexaneAtom0, rightCyclohexaneAtom1); IBond rightCyclohexaneAtom1Atom2 = ringSet.Builder.NewBond(rightCyclohexaneAtom1, rightCyclohexaneAtom2); IBond rightCyclohexane2rightCyclopentane1 = ringSet.Builder.NewBond(rightCyclohexaneAtom2, rightCyclopentane.Atoms[1]); IBond rightCyclohexane5rightCyclopentane0 = ringSet.Builder.NewBond(rightCyclohexaneAtom5, rightCyclopentane.Atoms[0]); IBond rightCyclohexaneAtom0Atom5 = ringSet.Builder.NewBond(rightCyclohexaneAtom0, rightCyclohexaneAtom5); rightCyclohexane.Atoms.Add(rightCyclohexaneAtom0); rightCyclohexane.Atoms.Add(rightCyclohexaneAtom1); rightCyclohexane.Atoms.Add(rightCyclohexaneAtom2); rightCyclohexane.Atoms.Add(rightCyclopentane.Atoms[1]); rightCyclohexane.Atoms.Add(rightCyclopentane.Atoms[0]); rightCyclohexane.Atoms.Add(rightCyclohexaneAtom5); rightCyclohexane.Bonds.Add(rightCyclohexaneAtom0Atom1); rightCyclohexane.Bonds.Add(rightCyclohexaneAtom1Atom2); rightCyclohexane.Bonds.Add(rightCyclohexane2rightCyclopentane1); rightCyclohexane.Bonds.Add(rightCyclopentane.GetBond(rightCyclopentane.Atoms[0], rightCyclopentane.Atoms[1])); rightCyclohexane.Bonds.Add(rightCyclohexane5rightCyclopentane0); rightCyclohexane.Bonds.Add(rightCyclohexaneAtom0Atom5); ringSet.Add(leftCyclohexane); ringSet.Add(leftCyclopentane); ringSet.Add(rightCyclopentane); ringSet.Add(rightCyclohexane); // Get connected rings var connectedRings = ringSet.GetConnectedRings(leftCyclohexane); // Iterate over the connectedRings and fail if any duplicate is found IList <IRing> foundRings = new List <IRing>(); foreach (var container in connectedRings) { IRing connectedRing = (IRing)container; if (foundRings.Contains(connectedRing)) { Assert.Fail("The list of connected rings contains duplicates."); } foundRings.Add(connectedRing); } }