/// <summary> /// Recognise the cyclic carbohydrate projections. /// </summary> /// <param name="projections">the types of projections to recognise</param> /// <returns>recognised stereocenters</returns> public IEnumerable <IStereoElement <IChemObject, IChemObject> > Recognise(ICollection <Projection> projections) { if (!projections.Contains(Projection.Haworth) && !projections.Contains(Projection.Chair)) { yield break; } var ringSearch = new RingSearch(container, graph); foreach (var isolated in ringSearch.Isolated()) { if (isolated.Length < 5 || isolated.Length > 7) { continue; } var cycle = Arrays.CopyOf(GraphUtil.Cycle(graph, isolated), isolated.Length); var points = CoordinatesOfCycle(cycle, container); var turns = GetTurns(points); var projection = WoundProjection.OfTurns(turns); if (!projections.Contains(projection.Projection)) { continue; } // ring is not aligned correctly for Haworth if (projection.Projection == Projection.Haworth && !CheckHaworthAlignment(points)) { continue; } var horizontalXy = HorizontalOffset(points, turns, projection.Projection); // near vertical, should also flag as potentially ambiguous if (1 - Math.Abs(horizontalXy.Y) < QuartCardinalityThreshold) { continue; } var above = (int[])cycle.Clone(); var below = (int[])cycle.Clone(); if (!AssignSubstituents(cycle, above, below, projection, horizontalXy)) { continue; } foreach (var center in NewTetrahedralCenters(cycle, above, below, projection)) { yield return(center); } } yield break; }
/// <summary> /// Compute all rings up to and including the <paramref name="maxRingSize"/>. The /// container is first partitioned into ring systems which are then processed /// separately. If the molecule has already be partitioned, consider using <see cref="FindAllRingsInIsolatedRingSystem(IAtomContainer, int)"/>. /// </summary> /// <param name="container">The AtomContainer to be searched for rings</param> /// <param name="maxRingSize">Maximum ring size to consider. Provides a possible /// breakout from recursion for complex compounds.</param> /// <returns>A RingSet with all rings in the AtomContainer</returns> /// <exception cref="CDKException">An exception thrown if the threshold was exceeded</exception> public IRingSet FindAllRings(IAtomContainer container, int maxRingSize) { var edges = EdgeToBondMap.WithSpaceFor(container); var graph = GraphUtil.ToAdjList(container, edges); var rs = new RingSearch(container, graph); var ringSet = container.Builder.NewRingSet(); // don't need to run on isolated rings, just need to put vertices in // cyclic order foreach (var isolated in rs.Isolated()) { if (isolated.Length <= maxRingSize) { var ring = ToRing(container, edges, GraphUtil.Cycle(graph, isolated)); ringSet.Add(ring); } } // for each set of fused cyclic vertices run the separate search foreach (var fused in rs.Fused()) { var ac = new AllCycles(GraphUtil.Subgraph(graph, fused), Math.Min(maxRingSize, fused.Length), threshold.Value); if (!ac.Completed) { throw new CDKException("Threshold exceeded for AllRingsFinder"); } foreach (var path in ac.GetPaths()) { IRing ring = ToRing(container, edges, path, fused); ringSet.Add(ring); } } return(ringSet); }