示例#1
0
        /// <summary>
        /// Hide the repeated atoms and bonds of a multiple group. We hide al atoms that
        /// belong to the group unless they are defined in the parent atom list. Any
        /// bond to those atoms that is not a crossing bond or one connecting atoms in
        /// the parent list is hidden.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <param name="sgroup">multiple group display shortcut</param>
        private static void HideMultipleParts(IAtomContainer container, Sgroup sgroup)
        {
            var crossing    = sgroup.Bonds;
            var atoms       = sgroup.Atoms;
            var parentAtoms = (ICollection <IAtom>)sgroup.GetValue(SgroupKey.CtabParentAtomList);

            foreach (var bond in container.Bonds)
            {
                if (parentAtoms.Contains(bond.Begin) && parentAtoms.Contains(bond.End))
                {
                    continue;
                }
                if (atoms.Contains(bond.Begin) || atoms.Contains(bond.End))
                {
                    StandardGenerator.Hide(bond);
                }
            }
            foreach (var atom in atoms)
            {
                if (!parentAtoms.Contains(atom))
                {
                    StandardGenerator.Hide(atom);
                }
            }
            foreach (var bond in crossing)
            {
                StandardGenerator.Unhide(bond);
            }
        }
示例#2
0
        public void CopySgroups()
        {
            List <Sgroup> sgroups = new List <Sgroup>();
            IAtom         a1      = new Mock <IAtom>().Object;
            IAtom         a2      = new Mock <IAtom>().Object;
            IBond         b1      = new Mock <IBond>().Object;
            IBond         b2      = new Mock <IBond>().Object;
            Sgroup        sgroup  = new Sgroup
            {
                Type      = SgroupType.CtabStructureRepeatUnit,
                Subscript = "n"
            };

            sgroup.Atoms.Add(a1);
            sgroup.Atoms.Add(a2);
            sgroup.Bonds.Add(b1);
            sgroup.Bonds.Add(b2);
            sgroups.Add(sgroup);
            var    copied       = SgroupManipulator.Copy(sgroups, null);
            Sgroup copiedSgroup = copied[0];

            Assert.AreNotSame(sgroup, copiedSgroup);
            Assert.AreEqual(sgroup.Type, copiedSgroup.Type);
            Assert.AreEqual(sgroup.Subscript, copiedSgroup.Subscript);
            Assert.IsTrue(Compares.AreDeepEqual(sgroup.Atoms, copiedSgroup.Atoms));
            Assert.IsTrue(Compares.AreDeepEqual(sgroup.Bonds, copiedSgroup.Bonds));
        }
示例#3
0
        public void WriteSRUs()
        {
            var mol = builder.NewAtomContainer();

            mol.Atoms.Add(builder.NewAtom("C"));
            mol.Atoms.Add(builder.NewAtom("C"));
            mol.Atoms.Add(builder.NewAtom("O"));
            mol.Atoms.Add(builder.NewAtom("O"));
            mol.AddBond(mol.Atoms[0], mol.Atoms[1], BondOrder.Single);
            mol.AddBond(mol.Atoms[1], mol.Atoms[2], BondOrder.Single);
            mol.AddBond(mol.Atoms[2], mol.Atoms[3], BondOrder.Single);
            mol.Atoms[0].ImplicitHydrogenCount = 3;
            mol.Atoms[1].ImplicitHydrogenCount = 2;
            mol.Atoms[2].ImplicitHydrogenCount = 0;
            mol.Atoms[3].ImplicitHydrogenCount = 1;
            var sgroups = new List <Sgroup>();
            var sgroup  = new Sgroup();

            sgroup.Atoms.Add(mol.Atoms[1]);
            sgroup.Atoms.Add(mol.Atoms[2]);
            sgroup.Bonds.Add(mol.Bonds[0]);
            sgroup.Bonds.Add(mol.Bonds[2]);
            sgroup.Type      = SgroupType.CtabStructureRepeatUnit;
            sgroup.Subscript = "n";
            sgroup.PutValue(SgroupKey.CtabConnectivity, "HH");
            sgroups.Add(sgroup);
            mol.SetCtabSgroups(sgroups);
            var res = WriteToStr(mol);

            Assert.IsTrue(res.Contains("M  V30 1 SRU 0 ATOMS=(2 2 3) XBONDS=(2 1 3) LABEL=n CONNECT=HH\n"));
        }
示例#4
0
        public async Task <IActionResult> Edit(int id, [Bind("SgroupId,SgroupName,CourseName,Specialization")] Sgroup sgroup)
        {
            if (id != sgroup.SgroupId)
            {
                return(NotFound());
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(sgroup);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!SgroupExists(sgroup.SgroupId))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        throw;
                    }
                }
                return(RedirectToAction(nameof(Index)));
            }
            return(View(sgroup));
        }
示例#5
0
        private static string GetSgroupPolymerKey(Sgroup sgroup)
        {
            switch (sgroup.Type)
            {
            case SgroupType.CtabStructureRepeatUnit:
                return("n");

            case SgroupType.CtabMonomer:
                return("mon");

            case SgroupType.CtabMer:
                return("mer");

            case SgroupType.CtabCopolymer:
                string subtype = (string)sgroup.GetValue(SgroupKey.CtabSubType);
                if (subtype == null)
                {
                    return("co");
                }
                switch (subtype)
                {
                case "RAN":
                    return("ran");

                case "ALT":
                    return("alt");

                case "BLO":
                    return("blk");
                }
                goto case SgroupType.CtabCrossLink;

            case SgroupType.CtabCrossLink:
                return("xl");

            case SgroupType.CtabModified:
                return("mod");

            case SgroupType.CtabMixture:
                return("mix");

            case SgroupType.CtabFormulation:
                return("f");

            case SgroupType.CtabAnyPolymer:
                return("any");

            case SgroupType.CtabGeneric:
                return("gen");

            case SgroupType.CtabComponent:
                return("c");

            case SgroupType.CtabGraft:
                return("grf");

            default:
                throw new ArgumentException($"{sgroup.Type} is not proper.");
            }
        }
示例#6
0
        /// <summary>
        /// Checks whether the given abbreviation Sgroup either has no highlight or is fully highlighted. If an
        /// abbreviation is partially highlighted we don't want to contract it as this would hide the part
        /// being highlighted.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <param name="sgroup">abbreviation Sgroup</param>
        /// <returns>the abbreviation can be contracted</returns>
        private static bool CheckAbbreviationHighlight(IAtomContainer container, Sgroup sgroup)
        {
            Debug.Assert(sgroup.Type == SgroupType.CtabAbbreviation);

            var sgroupAtoms    = sgroup.Atoms;
            int atomHighlight  = 0;
            int bondHighlight  = 0;
            int numSgroupAtoms = sgroupAtoms.Count;
            int numSgroupBonds = 0;

            Color?color    = null;
            Color?refcolor = null;

            foreach (var atom in sgroupAtoms)
            {
                if ((color = atom.GetProperty <Color?>(StandardGenerator.HighlightColorKey)) != null)
                {
                    atomHighlight++;
                    if (refcolor == null)
                    {
                        refcolor = color;
                    }
                    else if (!color.Equals(refcolor))
                    {
                        return(false); // multi-colored
                    }
                }
                else if (atomHighlight != 0)
                {
                    return(false); // fail fast
                }
            }
            foreach (var bond in container.Bonds)
            {
                var beg = bond.Begin;
                var end = bond.End;
                if (sgroupAtoms.Contains(beg) && sgroupAtoms.Contains(end))
                {
                    numSgroupBonds++;
                    if ((color = bond.GetProperty <Color?>(StandardGenerator.HighlightColorKey)) != null)
                    {
                        bondHighlight++;
                        if (refcolor == null)
                        {
                            refcolor = color;
                        }
                        else if (!color.Equals(refcolor))
                        {
                            return(false); // multi-colored
                        }
                    }
                    else if (bondHighlight != 0)
                    {
                        return(false); // fail fast
                    }
                }
            }
            return(atomHighlight + bondHighlight == 0 || (atomHighlight == numSgroupAtoms &&
                                                          bondHighlight == numSgroupBonds));
        }
        private IRenderingElement GenerateAbbreviationSgroup(IAtomContainer mol, Sgroup sgroup)
        {
            string label = sgroup.Subscript;

            // already handled by symbol remapping
            if (sgroup.Bonds.Count > 0 || string.IsNullOrEmpty(label))
            {
                return(new ElementGroup());
            }
            if (!CheckAbbreviationHighlight(mol, sgroup))
            {
                return(new ElementGroup());
            }
            // we're showing a label where there were no atoms before, we put it in the
            // middle of all of those which were hidden
            var sgroupAtoms = sgroup.Atoms;

            Debug.Assert(sgroupAtoms.Any());

            var highlight = sgroupAtoms.First().GetProperty <Color>(StandardGenerator.HighlightColorKey);
            var style     = parameters.GetHighlighting();
            var glowWidth = parameters.GetOuterGlowWidth();

            Vector2 labelCoords = GeometryUtil.Get2DCenter(sgroupAtoms);

            ElementGroup labelgroup = new ElementGroup();

            foreach (var outline in atomGenerator.GenerateAbbreviatedSymbol(label, HydrogenPosition.Right)
                     .Resize(1 / scale, 1 / -scale)
                     .GetOutlines())
            {
                if (highlight != null && style == HighlightStyle.Colored)
                {
                    labelgroup.Add(GeneralPath.ShapeOf(outline, highlight));
                }
                else
                {
                    labelgroup.Add(GeneralPath.ShapeOf(outline, foreground));
                }
            }

            if (highlight != null && style == HighlightStyle.OuterGlow)
            {
                ElementGroup group = new ElementGroup
                {
                    // outer glow needs to be being the label
                    StandardGenerator.OuterGlow(labelgroup, highlight, glowWidth, stroke),
                    labelgroup
                };
                return(group);
            }
            else
            {
                return(MarkedElement.MarkupAtom(labelgroup, null));
            }
        }
示例#8
0
        public async Task <IActionResult> Create([Bind("SgroupId,SgroupName,CourseName,Specialization")] Sgroup sgroup)
        {
            if (ModelState.IsValid)
            {
                _context.Add(sgroup);
                await _context.SaveChangesAsync();

                return(RedirectToAction(nameof(Index)));
            }
            return(View(sgroup));
        }
示例#9
0
        private IRenderingElement GenerateMixtureSgroup(Sgroup sgroup)
        {
            // draw the brackets
            // TODO - mixtures normally have attached Sgroup data
            // TODO - e.g. COMPONENT_FRACTION, ACTIVITY_TYPE, WEIGHT_PERCENT
            var brackets = (IList <SgroupBracket>)sgroup.GetValue(SgroupKey.CtabBracket);

            if (brackets != null)
            {
                var    type      = sgroup.Type;
                string subscript = "?";
                switch (type)
                {
                case SgroupType.CtabComponent:
                    var compNum = (int?)sgroup.GetValue(SgroupKey.CtabComponentNumber);
                    if (compNum != null)
                    {
                        subscript = "c" + compNum.ToString();
                    }
                    else
                    {
                        subscript = "c";
                    }
                    break;

                case SgroupType.CtabMixture:
                    subscript = "mix";
                    break;

                case SgroupType.CtabFormulation:
                    subscript = "f";
                    break;
                }

                return(GenerateSgroupBrackets(sgroup,
                                              brackets,
                                              null,
                                              subscript,
                                              null));
            }
            else
            {
                return(new ElementGroup());
            }
        }
示例#10
0
        private IRenderingElement GenerateMultipleSgroup(Sgroup sgroup)
        {
            // just draw the brackets - multiplied group parts have already been hidden in prep phase
            var brackets = (IList <SgroupBracket>)sgroup.GetValue(SgroupKey.CtabBracket);

            if (brackets != null)
            {
                return(GenerateSgroupBrackets(sgroup,
                                              brackets,
                                              Dictionaries.Empty <IAtom, AtomSymbol>(),
                                              (string)sgroup.GetValue(SgroupKey.CtabSubScript),
                                              null));
            }
            else
            {
                return(new ElementGroup());
            }
        }
示例#11
0
        public void DontOverwriteExistingSgroups()
        {
            var factory = new Abbreviations {
                "*CCC Bu"
            };
            var mol    = Smi("c1ccccc1CCC");
            var sgroup = new Sgroup();

            sgroup.Atoms.Add(mol.Atoms[6]);
            sgroup.Atoms.Add(mol.Atoms[7]);
            sgroup.Atoms.Add(mol.Atoms[8]);
            sgroup.Type      = SgroupType.CtabAbbreviation;
            sgroup.Subscript = "n-Bu";
            mol.SetCtabSgroups(new[] { sgroup });
            var sgroups = factory.Generate(mol);

            Assert.AreEqual(0, sgroups.Count);
        }
示例#12
0
        public void CopySgroups2()
        {
            var sgroups = new List <Sgroup>();
            var replace = new CDKObjectMap();

            IAtom a1 = new Mock <IAtom>().Object;
            IAtom a2 = new Mock <IAtom>().Object;
            IBond b1 = new Mock <IBond>().Object;
            IBond b2 = new Mock <IBond>().Object;

            IAtom a1copy = new Mock <IAtom>().Object;
            IAtom a2copy = new Mock <IAtom>().Object;
            IBond b1copy = new Mock <IBond>().Object;
            IBond b2copy = new Mock <IBond>().Object;

            replace.Add(a1, a1copy);
            replace.Add(a2, a2copy);
            replace.Add(b1, b1copy);
            replace.Add(b2, b2copy);

            Sgroup sgroup = new Sgroup
            {
                Type      = SgroupType.CtabStructureRepeatUnit,
                Subscript = "n"
            };

            sgroup.Atoms.Add(a1);
            sgroup.Atoms.Add(a2);
            sgroup.Bonds.Add(b1);
            sgroup.Bonds.Add(b2);
            sgroups.Add(sgroup);
            var    copied       = SgroupManipulator.Copy(sgroups, replace);
            Sgroup copiedSgroup = copied[0];

            Assert.AreNotSame(sgroup, copiedSgroup);
            Assert.AreEqual(sgroup.Type, copiedSgroup.Type);
            Assert.AreEqual(sgroup.Subscript, copiedSgroup.Subscript);
            Assert.IsFalse(Compares.AreDeepEqual(sgroup.Atoms, copiedSgroup.Atoms));
            Assert.IsFalse(Compares.AreDeepEqual(sgroup.Bonds, copiedSgroup.Bonds));
            Assert.IsTrue(copiedSgroup.Atoms.Contains(a1copy));
            Assert.IsTrue(copiedSgroup.Atoms.Contains(a2copy));
            Assert.IsTrue(copiedSgroup.Bonds.Contains(b1copy));
            Assert.IsTrue(copiedSgroup.Bonds.Contains(b2copy));
        }
示例#13
0
        public void WriteMultipleGroup()
        {
            int repeatAtoms = 50;
            var mol         = builder.NewAtomContainer();

            mol.Atoms.Add(builder.NewAtom("C"));
            for (int i = 0; i < repeatAtoms; i++)
            {
                mol.Atoms.Add(builder.NewAtom("C"));
            }
            mol.Atoms.Add(builder.NewAtom("O"));
            mol.AddBond(mol.Atoms[0], mol.Atoms[1], BondOrder.Single);
            for (int i = 0; i < repeatAtoms; i++)
            {
                mol.AddBond(mol.Atoms[i + 1], mol.Atoms[i + 2], BondOrder.Single);
            }
            mol.Atoms[0].ImplicitHydrogenCount = 3;
            for (int i = 0; i < repeatAtoms; i++)
            {
                mol.Atoms[1 + i].ImplicitHydrogenCount = 2;
            }
            mol.Atoms[mol.Atoms.Count - 1].ImplicitHydrogenCount = 1;

            var sgroups = new List <Sgroup>();
            var sgroup  = new Sgroup();

            for (int i = 0; i < repeatAtoms; i++)
            {
                sgroup.Atoms.Add(mol.Atoms[i + 1]);
            }
            sgroup.Bonds.Add(mol.Bonds[0]);
            sgroup.Bonds.Add(mol.Bonds[mol.Bonds.Count - 1]);
            sgroup.PutValue(SgroupKey.CtabParentAtomList, new[] { mol.Atoms[1] });
            sgroup.Type      = SgroupType.CtabMultipleGroup;
            sgroup.Subscript = repeatAtoms.ToString();
            sgroups.Add(sgroup);
            mol.SetCtabSgroups(sgroups);
            var res = WriteToStr(mol);

            Assert.IsTrue(res.Contains("M  V30 1 MUL 0 ATOMS=(50 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2-\n"
                                       + "M  V30 2 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 -\n"
                                       + "M  V30 46 47 48 49 50 51) XBONDS=(2 1 51) MULT=50 PATOMS=(1 2)\n"));
        }
示例#14
0
        private Sgroup GetAbbr(IAtomContainer part)
        {
            string label;
            string cansmi;

            if (part.Atoms.Count == 1)
            {
                var atom = part.Atoms[0];
                label = GetBasicElementSymbol(atom);
                if (label != null)
                {
                    var sgroup = new Sgroup
                    {
                        Type      = SgroupType.CtabAbbreviation,
                        Subscript = label
                    };
                    sgroup.Atoms.Add(atom);
                    return(sgroup);
                }
            }
            else
            {
                cansmi = usmigen.Create(part);
                if (disconnectedAbbreviations.TryGetValue(cansmi, out label) && !disabled.Contains(label))
                {
                    var sgroup = new Sgroup
                    {
                        Type      = SgroupType.CtabAbbreviation,
                        Subscript = label
                    };
                    foreach (var atom in part.Atoms)
                    {
                        sgroup.Atoms.Add(atom);
                    }
                    return(sgroup);
                }
            }
            return(null);
        }
示例#15
0
        public void TestSgroupAtomListWrapping()
        {
            IAtomContainer mol = TestMoleculeFactory.MakeEthylPropylPhenantren();

            Sgroup sgroup = new Sgroup();

            foreach (var atom in mol.Atoms)
            {
                sgroup.Atoms.Add(atom);
            }
            mol.SetCtabSgroups(new[] { sgroup });

            StringWriter sw = new StringWriter();

            using (MDLV2000Writer mdlw = new MDLV2000Writer(sw))
            {
                mdlw.Write(mol);
                string output = sw.ToString();
                Assert.IsTrue(output.Contains("M  SAL   1 15"));
                Assert.IsTrue(output.Contains("M  SAL   1  4"));
            }
        }
示例#16
0
        /// <summary>
        /// Find all enabled abbreviations in the provided molecule. They are not
        /// added to the existing Sgroups and may need filtering.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <returns>list of new abbreviation Sgroups</returns>
        public IList <Sgroup> Generate(IAtomContainer mol)
        {
            // mark which atoms have already been abbreviated or are
            // part of an existing Sgroup
            var usedAtoms = new HashSet <IAtom>();
            var sgroups   = mol.GetCtabSgroups();

            if (sgroups != null)
            {
                foreach (var sgroup in sgroups)
                {
                    foreach (var atom in sgroup.Atoms)
                    {
                        usedAtoms.Add(atom);
                    }
                }
            }

            var newSgroups = new List <Sgroup>();

            // disconnected abbreviations, salts, common reagents, large compounds
            if (!usedAtoms.Any())
            {
                try
                {
                    var    copy   = AtomContainerManipulator.CopyAndSuppressedHydrogens(mol);
                    string cansmi = usmigen.Create(copy);
                    if (disconnectedAbbreviations.TryGetValue(cansmi, out string label) && !disabled.Contains(label) && ContractToSingleLabel)
                    {
                        var sgroup = new Sgroup
                        {
                            Type      = SgroupType.CtabAbbreviation,
                            Subscript = label
                        };
                        foreach (var atom in mol.Atoms)
                        {
                            sgroup.Atoms.Add(atom);
                        }
                        return(new[] { sgroup });
                    }
                    else if (cansmi.Contains("."))
                    {
                        var parts = ConnectivityChecker.PartitionIntoMolecules(mol);

                        // leave one out
                        Sgroup best = null;
                        for (int i = 0; i < parts.Count; i++)
                        {
                            var a = parts[i];
                            var b = a.Builder.NewAtomContainer();
                            for (int j = 0; j < parts.Count; j++)
                            {
                                if (j != i)
                                {
                                    b.Add(parts[j]);
                                }
                            }
                            var sgroup1 = GetAbbr(a);
                            var sgroup2 = GetAbbr(b);
                            if (sgroup1 != null && sgroup2 != null && ContractToSingleLabel)
                            {
                                var combined = new Sgroup();
                                label = null;
                                foreach (var atom in sgroup1.Atoms)
                                {
                                    combined.Atoms.Add(atom);
                                }
                                foreach (var atom in sgroup2.Atoms)
                                {
                                    combined.Atoms.Add(atom);
                                }
                                if (sgroup1.Subscript.Length > sgroup2.Subscript.Length)
                                {
                                    combined.Subscript = sgroup1.Subscript + String_Interpunct + sgroup2.Subscript;
                                }
                                else
                                {
                                    combined.Subscript = sgroup2.Subscript + String_Interpunct + sgroup1.Subscript;
                                }
                                combined.Type = SgroupType.CtabAbbreviation;
                                return(new[] { combined });
                            }
                            if (sgroup1 != null && (best == null || sgroup1.Atoms.Count > best.Atoms.Count))
                            {
                                best = sgroup1;
                            }
                            if (sgroup2 != null && (best == null || sgroup2.Atoms.Count < best.Atoms.Count))
                            {
                                best = sgroup2;
                            }
                        }
                        if (best != null)
                        {
                            newSgroups.Add(best);
                            foreach (var atom in best.Atoms)
                            {
                                usedAtoms.Add(atom);
                            }
                        }
                    }
                }
                catch (CDKException)
                {
                }
            }

            var fragments  = GenerateFragments(mol);
            var sgroupAdjs = new MultiDictionary <IAtom, Sgroup>();

            foreach (var frag in fragments)
            {
                try
                {
                    var smi = usmigen.Create(AtomContainerManipulator.CopyAndSuppressedHydrogens(frag));
                    if (!connectedAbbreviations.TryGetValue(smi, out string label) || disabled.Contains(label))
                    {
                        continue;
                    }

                    bool overlap = false;

                    // note: first atom is '*'
                    var numAtoms = frag.Atoms.Count;
                    var numBonds = frag.Bonds.Count;
                    for (int i = 1; i < numAtoms; i++)
                    {
                        if (usedAtoms.Contains(frag.Atoms[i]))
                        {
                            overlap = true;
                            break;
                        }
                    }

                    // overlaps with previous assignment
                    if (overlap)
                    {
                        continue;
                    }

                    // create new abbreviation Sgroup
                    var sgroup = new Sgroup
                    {
                        Type      = SgroupType.CtabAbbreviation,
                        Subscript = label
                    };

                    var   attachBond = frag.Bonds[0].GetProperty <IBond>(PropertyName_CutBond);
                    IAtom attachAtom = null;
                    sgroup.Bonds.Add(attachBond);
                    for (int i = 1; i < numAtoms; i++)
                    {
                        var atom = frag.Atoms[i];
                        usedAtoms.Add(atom);
                        sgroup.Atoms.Add(atom);
                        if (attachBond.Begin.Equals(atom))
                        {
                            attachAtom = attachBond.End;
                        }
                        else if (attachBond.End.Equals(atom))
                        {
                            attachAtom = attachBond.Begin;
                        }
                    }

                    if (attachAtom != null)
                    {
                        sgroupAdjs.Add(attachAtom, sgroup);
                    }
                    newSgroups.Add(sgroup);
                }
                catch (CDKException)
                {
                    // ignore
                }
            }

            if (!ContractOnHetero)
            {
                return(newSgroups);
            }

            // now collapse
            foreach (var attach in mol.Atoms)
            {
                if (usedAtoms.Contains(attach))
                {
                    continue;
                }

                // skip charged or isotopic labelled, C or R/*, H, He
                if ((attach.FormalCharge != null && attach.FormalCharge != 0) ||
                    attach.MassNumber != null ||
                    attach.AtomicNumber == 6 ||
                    attach.AtomicNumber < 2)
                {
                    continue;
                }

                var hcount   = attach.ImplicitHydrogenCount.Value;
                var xatoms   = new HashSet <IAtom>();
                var xbonds   = new HashSet <IBond>();
                var newbonds = new HashSet <IBond>();
                xatoms.Add(attach);

                var nbrSymbols = new List <string>();
                var todelete   = new HashSet <Sgroup>();
                foreach (var sgroup in sgroupAdjs[attach])
                {
                    if (ContainsChargeChar(sgroup.Subscript))
                    {
                        continue;
                    }
                    if (sgroup.Bonds.Count != 1)
                    {
                        continue;
                    }
                    var xbond = sgroup.Bonds.First();
                    xbonds.Add(xbond);
                    foreach (var a in sgroup.Atoms)
                    {
                        xatoms.Add(a);
                    }
                    if (attach.Symbol.Length == 1 &&
                        char.IsLower(sgroup.Subscript[0]))
                    {
                        if (ChemicalElement.OfSymbol(attach.Symbol + sgroup.Subscript[0]) != ChemicalElement.R)
                        {
                            goto continue_collapse;
                        }
                    }
                    nbrSymbols.Add(sgroup.Subscript);
                    todelete.Add(sgroup);
                }
                int numSGrpNbrs = nbrSymbols.Count;
                foreach (var bond in mol.GetConnectedBonds(attach))
                {
                    if (!xbonds.Contains(bond))
                    {
                        var nbr = bond.GetOther(attach);
                        // contract terminal bonds
                        if (mol.GetConnectedBonds(nbr).Count() == 1)
                        {
                            if (nbr.MassNumber != null ||
                                (nbr.FormalCharge != null && nbr.FormalCharge != 0))
                            {
                                newbonds.Add(bond);
                            }
                            else if (nbr.AtomicNumber == 1)
                            {
                                hcount++;
                                xatoms.Add(nbr);
                            }
                            else if (nbr.AtomicNumber > 0)
                            {
                                nbrSymbols.Add(NewSymbol(nbr.AtomicNumber, nbr.ImplicitHydrogenCount.Value, false));
                                xatoms.Add(nbr);
                            }
                        }
                        else
                        {
                            newbonds.Add(bond);
                        }
                    }
                }

                // reject if no symbols
                // reject if no bonds (<1), except if all symbols are identical... (HashSet.size==1)
                // reject if more that 2 bonds
                if (!nbrSymbols.Any() ||
                    newbonds.Count < 1 && (new HashSet <string>(nbrSymbols).Count != 1) ||
                    newbonds.Count > 2)
                {
                    continue;
                }

                // create the symbol
                var sb = new StringBuilder();
                sb.Append(NewSymbol(attach.AtomicNumber, hcount, newbonds.Count == 0));
                string prev  = null;
                int    count = 0;
                nbrSymbols.Sort((o1, o2) =>
                {
                    int cmp = o1.Length.CompareTo(o2.Length);
                    if (cmp != 0)
                    {
                        return(cmp);
                    }
                    return(o1.CompareTo(o2));
                });
                foreach (string nbrSymbol in nbrSymbols)
                {
                    if (nbrSymbol.Equals(prev))
                    {
                        count++;
                    }
                    else
                    {
                        bool useParen = count == 0 || CountUpper(prev) > 1 || (prev != null && nbrSymbol.StartsWith(prev));
                        AppendGroup(sb, prev, count, useParen);
                        prev  = nbrSymbol;
                        count = 1;
                    }
                }
                AppendGroup(sb, prev, count, false);

                // remove existing
                foreach (var e in todelete)
                {
                    newSgroups.Remove(e);
                }

                // create new
                var newSgroup = new Sgroup
                {
                    Type      = SgroupType.CtabAbbreviation,
                    Subscript = sb.ToString()
                };
                foreach (var bond in newbonds)
                {
                    newSgroup.Bonds.Add(bond);
                }
                foreach (var atom in xatoms)
                {
                    newSgroup.Atoms.Add(atom);
                }

                newSgroups.Add(newSgroup);
                foreach (var a in xatoms)
                {
                    usedAtoms.Add(a);
                }
continue_collapse:
                ;
            }

            return(newSgroups);
        }
示例#17
0
        private IRenderingElement GenerateSgroupBrackets(Sgroup sgroup,
                                                         IList <SgroupBracket> brackets,
                                                         IReadOnlyDictionary <IAtom, AtomSymbol> symbols,
                                                         string subscriptSuffix,
                                                         string superscriptSuffix)
        {
            // brackets are square by default (style:0)
            var  style  = (int?)sgroup.GetValue(SgroupKey.CtabBracketStyle);
            bool round  = style != null && style == 1;
            var  result = new ElementGroup();

            var atoms         = sgroup.Atoms;
            var crossingBonds = sgroup.Bonds;

            // easy to depict in correct orientation, we just
            // point each bracket at the atom of a crossing
            // bond that is 'in' the group - this scales
            // to more than two brackets

            // first we need to pair the brackets with the bonds
            var pairs = crossingBonds.Count == brackets.Count ? BracketBondPairs(brackets, crossingBonds) : Dictionaries.Empty <SgroupBracket, IBond>();

            // override bracket layout around single atoms to bring them in closer
            if (atoms.Count == 1)
            {
                var atom = atoms.First();

                // e.g. 2 HCL, 8 H2O etc.
                if (IsUnsignedInt(subscriptSuffix) &&
                    !crossingBonds.Any() &&
                    symbols.ContainsKey(atom))
                {
                    var prefix       = new TextOutline('·' + subscriptSuffix, font, emSize).Resize(1 / scale, 1 / -scale);
                    var prefixBounds = prefix.LogicalBounds;

                    var symbol = symbols[atom];

                    var bounds = symbol.GetConvexHull().Outline.Bounds;

                    // make slightly large
                    bounds = new Rect(bounds.Bottom - 2 * stroke,
                                      bounds.Left - 2 * stroke,
                                      bounds.Width + 4 * stroke,
                                      bounds.Height + 4 * stroke);

                    prefix = prefix.Translate(bounds.Bottom - prefixBounds.Top,
                                              symbol.GetAlignmentCenter().Y - prefixBounds.CenterY());

                    result.Add(GeneralPath.ShapeOf(prefix.GetOutline(), foreground));
                }
                // e.g. CC(O)nCC
                else if (crossingBonds.Count > 0)
                {
                    var scriptscale = labelScale;

                    var leftBracket  = new TextOutline("(", font, emSize).Resize(1 / scale, 1 / -scale);
                    var rightBracket = new TextOutline(")", font, emSize).Resize(1 / scale, 1 / -scale);

                    var leftCenter  = leftBracket.GetCenter();
                    var rightCenter = rightBracket.GetCenter();

                    if (symbols.ContainsKey(atom))
                    {
                        var symbol = symbols[atom];

                        var bounds = symbol.GetConvexHull().Outline.Bounds;
                        // make slightly large
                        bounds = new Rect(bounds.Left - 2 * stroke,
                                          bounds.Top - 2 * stroke,
                                          bounds.Width + 4 * stroke,
                                          bounds.Height + 4 * stroke);

                        leftBracket = leftBracket.Translate(bounds.Left - 0.1 - leftCenter.X,
                                                            symbol.GetAlignmentCenter().Y - leftCenter.Y);
                        rightBracket = rightBracket.Translate(bounds.Right + 0.1 - rightCenter.X,
                                                              symbol.GetAlignmentCenter().Y - rightCenter.Y);
                    }
                    else
                    {
                        var p = atoms.First().Point2D.Value;
                        leftBracket  = leftBracket.Translate(p.X - 0.2 - leftCenter.X, p.Y - leftCenter.Y);
                        rightBracket = rightBracket.Translate(p.X + 0.2 - rightCenter.X, p.Y - rightCenter.Y);
                    }

                    result.Add(GeneralPath.ShapeOf(leftBracket.GetOutline(), foreground));
                    result.Add(GeneralPath.ShapeOf(rightBracket.GetOutline(), foreground));

                    var rightBracketBounds = rightBracket.GetBounds();

                    // subscript/superscript suffix annotation
                    if (subscriptSuffix != null && subscriptSuffix.Any())
                    {
                        TextOutline subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(),
                                                                          new Vector2(rightBracketBounds.Right,
                                                                                      rightBracketBounds.Top - 0.1),
                                                                          new Vector2(-0.5 * rightBracketBounds.Width, 0),
                                                                          scriptscale));
                        result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                    }
                    if (superscriptSuffix != null && superscriptSuffix.Any())
                    {
                        var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(),
                                                                    new Vector2(rightBracketBounds.Right,
                                                                                rightBracketBounds.Bottom + 0.1),
                                                                    new Vector2(-rightBracketBounds.Width, 0),
                                                                    scriptscale));
                        result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                    }
                }
            }
            else if (pairs.Any())
            {
                SgroupBracket suffixBracket     = null;
                Vector2?      suffixBracketPerp = null;

                foreach (var e in pairs)
                {
                    var bracket     = e.Key;
                    var bond        = e.Value;
                    var inGroupAtom = atoms.Contains(bond.Begin) ? bond.Begin : bond.End;

                    var p1 = bracket.FirstPoint;
                    var p2 = bracket.SecondPoint;

                    var perp = VecmathUtil.NewPerpendicularVector(VecmathUtil.NewUnitVector(p1, p2));

                    // point the vector at the atom group
                    var midpoint = VecmathUtil.Midpoint(p1, p2);
                    if (Vector2.Dot(perp, VecmathUtil.NewUnitVector(midpoint, inGroupAtom.Point2D.Value)) < 0)
                    {
                        perp = Vector2.Negate(perp);
                    }
                    perp *= bracketDepth;

                    if (round)
                    {
                        result.Add(CreateRoundBracket(p1, p2, perp, midpoint));
                    }
                    else
                    {
                        result.Add(CreateSquareBracket(p1, p2, perp));
                    }

                    if (suffixBracket == null)
                    {
                        suffixBracket     = bracket;
                        suffixBracketPerp = perp;
                    }
                    else
                    {
                        // is this bracket better as a suffix?
                        var sp1      = suffixBracket.FirstPoint;
                        var sp2      = suffixBracket.SecondPoint;
                        var bestMaxX = Math.Max(sp1.X, sp2.X);
                        var thisMaxX = Math.Max(p1.X, p2.X);
                        var bestMaxY = Math.Max(sp1.Y, sp2.Y);
                        var thisMaxY = Math.Max(p1.Y, p2.Y);

                        // choose the most eastern or.. the most southern
                        var xDiff = thisMaxX - bestMaxX;
                        var yDiff = thisMaxY - bestMaxY;
                        if (xDiff > EQUIV_THRESHOLD || (xDiff > -EQUIV_THRESHOLD && yDiff < -EQUIV_THRESHOLD))
                        {
                            suffixBracket     = bracket;
                            suffixBracketPerp = perp;
                        }
                    }
                }

                // write the labels
                if (suffixBracket != null)
                {
                    var subSufPnt = suffixBracket.FirstPoint;
                    var supSufPnt = suffixBracket.SecondPoint;

                    // try to put the subscript on the bottom
                    var xDiff = subSufPnt.X - supSufPnt.X;
                    var yDiff = subSufPnt.Y - supSufPnt.Y;
                    if (yDiff > EQUIV_THRESHOLD || (yDiff > -EQUIV_THRESHOLD && xDiff > EQUIV_THRESHOLD))
                    {
                        var tmpP = subSufPnt;
                        subSufPnt = supSufPnt;
                        supSufPnt = tmpP;
                    }

                    // subscript/superscript suffix annotation
                    if (subscriptSuffix != null && subscriptSuffix.Any())
                    {
                        var subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(), subSufPnt, suffixBracketPerp.Value, labelScale));
                        result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                    }
                    if (superscriptSuffix != null && superscriptSuffix.Any())
                    {
                        var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(), supSufPnt, suffixBracketPerp.Value, labelScale));
                        result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                    }
                }
            }
            else if (brackets.Count == 2)
            {
                var b1p1 = brackets[0].FirstPoint;
                var b1p2 = brackets[0].SecondPoint;
                var b2p1 = brackets[1].FirstPoint;
                var b2p2 = brackets[1].SecondPoint;

                var b1vec = VecmathUtil.NewUnitVector(b1p1, b1p2);
                var b2vec = VecmathUtil.NewUnitVector(b2p1, b2p2);

                var b1pvec = VecmathUtil.NewPerpendicularVector(b1vec);
                var b2pvec = VecmathUtil.NewPerpendicularVector(b2vec);

                // Point the vectors at each other
                if (Vector2.Dot(b1pvec, VecmathUtil.NewUnitVector(b1p1, b2p1)) < 0)
                {
                    b1pvec = Vector2.Negate(b1pvec);
                }
                if (Vector2.Dot(b2pvec, VecmathUtil.NewUnitVector(b2p1, b1p1)) < 0)
                {
                    b2pvec = Vector2.Negate(b2pvec);
                }

                // scale perpendicular vectors by how deep the brackets need to be
                b1pvec *= bracketDepth;
                b2pvec *= bracketDepth;

                // bad brackets
                if (double.IsNaN(b1pvec.X) || double.IsNaN(b1pvec.Y) ||
                    double.IsNaN(b2pvec.X) || double.IsNaN(b2pvec.Y))
                {
                    return(result);
                }

                {
                    var path = new PathGeometry();

                    if (round)
                    {
                        {
                            // bracket 1 (cp: control point)
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b1p1.X + b1pvec.X, b1p1.Y + b1pvec.Y)
                            };
                            Vector2 cpb1 = VecmathUtil.Midpoint(b1p1, b1p2);
                            cpb1 += VecmathUtil.Negate(b1pvec);
                            var seg = new QuadraticBezierSegment
                            {
                                Point1 = new Point(cpb1.X, cpb1.Y),
                                Point2 = new Point(b1p2.X + b1pvec.X, b1p2.Y + b1pvec.Y)
                            };
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }

                        {
                            // bracket 2 (cp: control point)
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b2p1.X + b2pvec.X, b2p1.Y + b2pvec.Y)
                            };
                            var cpb2 = VecmathUtil.Midpoint(b2p1, b2p2);
                            cpb2 += VecmathUtil.Negate(b2pvec);
                            var seg = new QuadraticBezierSegment
                            {
                                Point1 = new Point(cpb2.X, cpb2.Y),
                                Point2 = new Point(b2p2.X + b2pvec.X, b2p2.Y + b2pvec.Y)
                            };
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }
                    }
                    else
                    {
                        {
                            // bracket 1
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b1p1.X + b1pvec.X, b1p1.Y + b1pvec.Y)
                            };
                            var seg = new PolyLineSegment();
                            seg.Points.Add(new Point(b1p1.X, b1p1.Y));
                            seg.Points.Add(new Point(b1p2.X, b1p2.Y));
                            seg.Points.Add(new Point(b1p2.X + b1pvec.X, b1p2.Y + b1pvec.Y));
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }

                        {
                            // bracket 2
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b2p1.X + b2pvec.X, b2p1.Y + b2pvec.Y)
                            };
                            var seg = new PolyLineSegment();
                            seg.Points.Add(new Point(b2p1.X, b2p1.Y));
                            seg.Points.Add(new Point(b2p2.X, b2p2.Y));
                            seg.Points.Add(new Point(b2p2.X + b2pvec.X, b2p2.Y + b2pvec.Y));
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }
                    }

                    result.Add(GeneralPath.OutlineOf(path, stroke, foreground));
                }

                // work out where to put the suffix labels (e.g. ht/hh/eu) superscript
                // and (e.g. n, xl, c, mix) subscript
                // TODO: could be improved
                var b1MaxX = Math.Max(b1p1.X, b1p2.X);
                var b2MaxX = Math.Max(b2p1.X, b2p2.X);
                var b1MaxY = Math.Max(b1p1.Y, b1p2.Y);
                var b2MaxY = Math.Max(b2p1.Y, b2p2.Y);

                var subSufPnt = b2p2;
                var supSufPnt = b2p1;
                var subpvec   = b2pvec;

                var bXDiff = b1MaxX - b2MaxX;
                var bYDiff = b1MaxY - b2MaxY;

                if (bXDiff > EQUIV_THRESHOLD || (bXDiff > -EQUIV_THRESHOLD && bYDiff < -EQUIV_THRESHOLD))
                {
                    subSufPnt = b1p2;
                    supSufPnt = b1p1;
                    subpvec   = b1pvec;
                }

                var xDiff = subSufPnt.X - supSufPnt.X;
                var yDiff = subSufPnt.Y - supSufPnt.Y;

                if (yDiff > EQUIV_THRESHOLD || (yDiff > -EQUIV_THRESHOLD && xDiff > EQUIV_THRESHOLD))
                {
                    var tmpP = subSufPnt;
                    subSufPnt = supSufPnt;
                    supSufPnt = tmpP;
                }

                // subscript/superscript suffix annotation
                if (subscriptSuffix != null && subscriptSuffix.Any())
                {
                    var subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(), subSufPnt, subpvec, labelScale));
                    result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                }
                if (superscriptSuffix != null && superscriptSuffix.Any())
                {
                    var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(), supSufPnt, subpvec, labelScale));
                    result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                }
            }
            return(result);
        }
示例#18
0
        /// <summary>
        /// Generates polymer Sgroup elements.
        /// </summary>
        /// <param name="sgroup">the Sgroup</param>
        /// <returns>the rendered elements (empty if no brackets defined)</returns>
        private IRenderingElement GeneratePolymerSgroup(Sgroup sgroup, IReadOnlyDictionary <IAtom, AtomSymbol> symbolMap)
        {
            // draw the brackets
            var brackets = (IList <SgroupBracket>)sgroup.GetValue(SgroupKey.CtabBracket);

            if (brackets != null)
            {
                var type = sgroup.Type;

                var subscript    = (string)sgroup.GetValue(SgroupKey.CtabSubScript);
                var connectivity = (string)sgroup.GetValue(SgroupKey.CtabConnectivity);

                switch (type)
                {
                case SgroupType.CtabCopolymer:
                    subscript = "co";
                    string subtype = (string)sgroup.GetValue(SgroupKey.CtabSubType);
                    if (string.Equals("RAN", subtype, StringComparison.Ordinal))
                    {
                        subscript = "ran";
                    }
                    else if (string.Equals("BLK", subtype, StringComparison.Ordinal))
                    {
                        subscript = "blk";
                    }
                    else if (string.Equals("ALT", subtype, StringComparison.Ordinal))
                    {
                        subscript = "alt";
                    }
                    break;

                case SgroupType.CtabCrossLink:
                    subscript = "xl";
                    break;

                case SgroupType.CtabAnyPolymer:
                    subscript = "any";
                    break;

                case SgroupType.CtabGraft:
                    subscript = "grf";
                    break;

                case SgroupType.CtabMer:
                    subscript = "mer";
                    break;

                case SgroupType.CtabMonomer:
                    subscript = "mon";
                    break;

                case SgroupType.CtabModified:
                    subscript = "mod";
                    break;

                case SgroupType.CtabStructureRepeatUnit:
                    if (subscript == null)
                    {
                        subscript = "n";
                    }
                    if (connectivity == null)
                    {
                        connectivity = "eu";
                    }
                    break;
                }

                // connectivity doesn't matter if symmetric... which is hard to test
                // here but we can certainly ignore it for single atoms (e.g. methylene)
                // also when we see brackets we presume head-to-tail repeating
                if ("ht".Equals(connectivity) || sgroup.Atoms.Count == 1)
                {
                    connectivity = null;
                }

                return(GenerateSgroupBrackets(sgroup,
                                              brackets,
                                              symbolMap,
                                              subscript,
                                              connectivity));
            }
            else
            {
                return(new ElementGroup());
            }
        }
示例#19
0
        private IRenderingElement GenerateAbbreviationSgroup(IAtomContainer mol, Sgroup sgroup)
        {
            string label = sgroup.Subscript;

            // already handled by symbol remapping
            if (sgroup.Bonds.Count > 0 || string.IsNullOrEmpty(label))
            {
                return(new ElementGroup());
            }
            if (!CheckAbbreviationHighlight(mol, sgroup))
            {
                return(new ElementGroup());
            }
            // we're showing a label where there were no atoms before, we put it in the
            // middle of all of those which were hidden
            var sgroupAtoms = sgroup.Atoms;

            Debug.Assert(sgroupAtoms.Any());

            var highlight = sgroupAtoms.First().GetProperty <Color>(StandardGenerator.HighlightColorKey);
            var style     = parameters.GetHighlighting();
            var glowWidth = parameters.GetOuterGlowWidth();

            Vector2 labelLocation;

            if (mol.Atoms.Count == sgroup.Atoms.Count)
            {
                labelLocation = GeometryUtil.Get2DCenter(sgroupAtoms);
            }
            else
            {
                // contraction of part of a fragment, e.g. SALT
                // here we work out the point we want to place the contract relative
                // to the SGroup Atoms
                labelLocation = new Vector2();
                var sgrpCenter = GeometryUtil.Get2DCenter(sgroupAtoms);
                var molCenter  = GeometryUtil.Get2DCenter(mol);
                var minMax     = GeometryUtil.GetMinMax(sgroupAtoms);
                var xDiff      = sgrpCenter.X - molCenter.X;
                var yDiff      = sgrpCenter.Y - molCenter.Y;
                if (xDiff > 0.1)
                {
                    labelLocation.X = minMax[0]; // min x
                    label           = INTERPUNCT + label;
                }
                else if (xDiff < -0.1)
                {
                    labelLocation.X = minMax[2]; // max x
                    label           = label + INTERPUNCT;
                }
                else
                {
                    labelLocation.X = sgrpCenter.X;
                    label           = INTERPUNCT + label;
                }
                if (yDiff > 0.1)
                {
                    labelLocation.Y = minMax[1]; // min y
                }
                else if (yDiff < -0.1)
                {
                    labelLocation.Y = minMax[3]; // max y
                }
                else
                {
                    labelLocation.Y = sgrpCenter.Y;
                }
            }

            var labelgroup = new ElementGroup();

            foreach (var outline in atomGenerator.GenerateAbbreviatedSymbol(label, HydrogenPosition.Right)
                     .Center(labelLocation.X, labelLocation.Y)
                     .Resize(1 / scale, 1 / -scale)
                     .GetOutlines())
            {
                if (highlight != null && style == HighlightStyle.Colored)
                {
                    labelgroup.Add(GeneralPath.ShapeOf(outline, highlight));
                }
                else
                {
                    labelgroup.Add(GeneralPath.ShapeOf(outline, foreground));
                }
            }

            if (highlight != null && style == HighlightStyle.OuterGlow)
            {
                var group = new ElementGroup
                {
                    // outer glow needs to be being the label
                    StandardGenerator.OuterGlow(labelgroup, highlight, glowWidth, stroke),
                    labelgroup
                };
                return(group);
            }
            else
            {
                return(MarkedElement.MarkupAtom(labelgroup, null));
            }
        }
示例#20
0
        /// <summary>
        /// Reads the bond atoms, order and stereo configuration.
        /// </summary>
        public void ReadBondBlock(IAtomContainer readData)
        {
            Trace.TraceInformation("Reading BOND block");
            bool foundEND = false;

            while (!foundEND)
            {
                string command = ReadCommand(ReadLine());
                if (string.Equals("END BOND", command, StringComparison.Ordinal))
                {
                    foundEND = true;
                }
                else
                {
                    Debug.WriteLine($"Parsing bond from: {command}");
                    var   tokenizer = Strings.Tokenize(command).GetEnumerator();
                    IBond bond      = readData.Builder.NewBond();
                    // parse the index
                    try
                    {
                        tokenizer.MoveNext();
                        string indexString = tokenizer.Current;
                        bond.Id = indexString;
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing bond index";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse the order
                    try
                    {
                        tokenizer.MoveNext();
                        string orderString = tokenizer.Current;
                        int    order       = int.Parse(orderString, NumberFormatInfo.InvariantInfo);
                        if (order >= 4)
                        {
                            Trace.TraceWarning("Query order types are not supported (yet). File a bug if you need it");
                        }
                        else
                        {
                            bond.Order = BondManipulator.CreateBondOrder((double)order);
                        }
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing bond index";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse index atom 1
                    try
                    {
                        tokenizer.MoveNext();
                        string indexAtom1String = tokenizer.Current;
                        int    indexAtom1       = int.Parse(indexAtom1String, NumberFormatInfo.InvariantInfo);
                        IAtom  atom1            = readData.Atoms[indexAtom1 - 1];
                        bond.Atoms.Add(atom1);  // bond.Atoms[0]
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing index atom 1 in bond";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }
                    // parse index atom 2
                    try
                    {
                        tokenizer.MoveNext();
                        string indexAtom2String = tokenizer.Current;
                        int    indexAtom2       = int.Parse(indexAtom2String, NumberFormatInfo.InvariantInfo);
                        IAtom  atom2            = readData.Atoms[indexAtom2 - 1];
                        bond.Atoms.Add(atom2); // bond.Atoms[1]
                    }
                    catch (Exception exception)
                    {
                        string error = "Error while parsing index atom 2 in bond";
                        Trace.TraceError(error);
                        Debug.WriteLine(exception);
                        throw new CDKException(error, exception);
                    }

                    var    endpts = new List <IAtom>();
                    string attach = null;

                    // the rest are key=value fields
                    if (command.IndexOf('=') != -1)
                    {
                        var options = ParseOptions(ExhaustStringTokenizer(tokenizer));
                        foreach (var key in options.Keys)
                        {
                            string value = options[key];
                            try
                            {
                                switch (key)
                                {
                                case "CFG":
                                    int configuration = int.Parse(value, NumberFormatInfo.InvariantInfo);
                                    if (configuration == 0)
                                    {
                                        bond.Stereo = BondStereo.None;
                                    }
                                    else if (configuration == 1)
                                    {
                                        bond.Stereo = BondStereo.Up;
                                    }
                                    else if (configuration == 2)
                                    {
                                        bond.Stereo = BondStereo.None;
                                    }
                                    else if (configuration == 3)
                                    {
                                        bond.Stereo = BondStereo.Down;
                                    }
                                    break;

                                case "ENDPTS":
                                    string[] endptStr = value.Split(' ');
                                    // skip first value that is count
                                    for (int i = 1; i < endptStr.Length; i++)
                                    {
                                        endpts.Add(readData.Atoms[int.Parse(endptStr[i], NumberFormatInfo.InvariantInfo) - 1]);
                                    }
                                    break;

                                case "ATTACH":
                                    attach = value;
                                    break;

                                default:
                                    Trace.TraceWarning("Not parsing key: " + key);
                                    break;
                                }
                            }
                            catch (Exception exception)
                            {
                                string error = "Error while parsing key/value " + key + "=" + value + ": "
                                               + exception.Message;
                                Trace.TraceError(error);
                                Debug.WriteLine(exception);
                                throw new CDKException(error, exception);
                            }
                        }
                    }

                    // storing bond
                    readData.Bonds.Add(bond);

                    // storing positional variation
                    if (string.Equals("ANY", attach, StringComparison.Ordinal))
                    {
                        Sgroup sgroup = new Sgroup {
                            Type = SgroupType.ExtMulticenter
                        };
                        sgroup.Atoms.Add(bond.Begin); // could be other end?
                        sgroup.Bonds.Add(bond);
                        foreach (var endpt in endpts)
                        {
                            sgroup.Atoms.Add(endpt);
                        }

                        var sgroups = readData.GetCtabSgroups();
                        if (sgroups == null)
                        {
                            readData.SetCtabSgroups(sgroups = new List <Sgroup>(4));
                        }
                        sgroups.Add(sgroup);
                    }

                    Debug.WriteLine($"Added bond: {bond}");
                }
            }
        }
示例#21
0
        /// <summary>
        /// Hide the atoms and bonds of a contracted abbreviation. If the abbreviations is attached
        /// we remap the attachment symbol to display the name. If there are no attachments the symbol
        /// we be added later ({@see #generateSgroups}).
        /// </summary>
        /// <param name="container">molecule</param>
        /// <param name="sgroup">abbreviation group display shortcut</param>
        private static void ContractAbbreviation(IAtomContainer container, IDictionary <IAtom, string> symbolRemap, Sgroup sgroup)
        {
            var crossing = sgroup.Bonds;
            var atoms    = sgroup.Atoms;

            // only do 0,1 attachments for now
            if (crossing.Count > 1)
            {
                return;
            }

            foreach (var atom in atoms)
            {
                StandardGenerator.Hide(atom);
            }
            foreach (var bond in container.Bonds)
            {
                if (atoms.Contains(bond.Begin) ||
                    atoms.Contains(bond.End))
                {
                    StandardGenerator.Hide(bond);
                }
            }
            foreach (var bond in crossing)
            {
                StandardGenerator.Unhide(bond);
                var a1 = bond.Begin;
                var a2 = bond.End;
                StandardGenerator.Unhide(a1);
                if (atoms.Contains(a1))
                {
                    symbolRemap[a1] = sgroup.Subscript;
                }
                StandardGenerator.Unhide(a2);
                if (atoms.Contains(a2))
                {
                    symbolRemap[a2] = sgroup.Subscript;
                }
            }
        }
示例#22
0
        /// <summary>
        /// Transfers the CXSMILES state onto the CDK atom/molecule data-structures.
        /// </summary>
        /// <param name="bldr">chem-object builder</param>
        /// <param name="atoms">atoms parsed from the molecule or reaction. Reaction molecules are list left to right.</param>
        /// <param name="atomToMol">look-up of atoms to molecules when connectivity/sgroups need modification</param>
        /// <param name="cxstate">the CXSMILES state to read from</param>
        private void AssignCxSmilesInfo(IChemObjectBuilder bldr,
                                        IChemObject chemObj,
                                        List <IAtom> atoms,
                                        Dictionary <IAtom, IAtomContainer> atomToMol,
                                        CxSmilesState cxstate)
        {
            // atom-labels - must be done first as we replace atoms
            if (cxstate.atomLabels != null)
            {
                foreach (var e in cxstate.atomLabels)
                {
                    // bounds check
                    if (e.Key >= atoms.Count)
                    {
                        continue;
                    }

                    var old    = atoms[e.Key];
                    var pseudo = bldr.NewPseudoAtom();
                    var val    = e.Value;

                    // specialised label handling
                    if (val.EndsWith("_p", StringComparison.Ordinal)) // pseudo label
                    {
                        val = val.Substring(0, val.Length - 2);
                    }
                    else if (val.StartsWith("_AP", StringComparison.Ordinal)) // attachment point
                    {
                        pseudo.AttachPointNum = ParseIntSafe(val.Substring(3));
                    }

                    pseudo.Label                 = val;
                    pseudo.AtomicNumber          = 0;
                    pseudo.ImplicitHydrogenCount = 0;
                    var mol = atomToMol[old];
                    AtomContainerManipulator.ReplaceAtomByAtom(mol, old, pseudo);
                    atomToMol.Add(pseudo, mol);
                    atoms[e.Key] = pseudo;
                }
            }

            // atom-values - set as comment, mirrors Molfile reading behavior
            if (cxstate.atomValues != null)
            {
                foreach (var e in cxstate.atomValues)
                {
                    atoms[e.Key].SetProperty(CDKPropertyName.Comment, e.Value);
                }
            }

            // atom-coordinates
            if (cxstate.atomCoords != null)
            {
                var numAtoms  = atoms.Count;
                var numCoords = cxstate.atomCoords.Count;
                var lim       = Math.Min(numAtoms, numCoords);
                if (cxstate.coordFlag)
                {
                    for (int i = 0; i < lim; i++)
                    {
                        atoms[i].Point3D = new Vector3(
                            cxstate.atomCoords[i][0],
                            cxstate.atomCoords[i][1],
                            cxstate.atomCoords[i][2]);
                    }
                }
                else
                {
                    for (int i = 0; i < lim; i++)
                    {
                        atoms[i].Point2D = new Vector2(
                            cxstate.atomCoords[i][0],
                            cxstate.atomCoords[i][1]);
                    }
                }
            }

            // atom radicals
            if (cxstate.atomRads != null)
            {
                foreach (var e in cxstate.atomRads)
                {
                    // bounds check
                    if (e.Key >= atoms.Count)
                    {
                        continue;
                    }

                    int count = 0;
                    var aa    = e.Value;
                    switch (e.Value)
                    {
                    case CxSmilesState.Radical.Monovalent:
                        count = 1;
                        break;

                    // no distinction in CDK between singled/triplet
                    case CxSmilesState.Radical.Divalent:
                    case CxSmilesState.Radical.DivalentSinglet:
                    case CxSmilesState.Radical.DivalentTriplet:
                        count = 2;
                        break;

                    // no distinction in CDK between doublet/quartet
                    case CxSmilesState.Radical.Trivalent:
                    case CxSmilesState.Radical.TrivalentDoublet:
                    case CxSmilesState.Radical.TrivalentQuartet:
                        count = 3;
                        break;
                    }
                    var atom = atoms[e.Key];
                    var mol  = atomToMol[atom];
                    while (count-- > 0)
                    {
                        mol.SingleElectrons.Add(bldr.NewSingleElectron(atom));
                    }
                }
            }

            var sgroupMap = new MultiDictionary <IAtomContainer, Sgroup>();

            // positional-variation
            if (cxstate.positionVar != null)
            {
                foreach (var e in cxstate.positionVar)
                {
                    var sgroup = new Sgroup {
                        Type = SgroupType.ExtMulticenter
                    };
                    var beg   = atoms[e.Key];
                    var mol   = atomToMol[beg];
                    var bonds = mol.GetConnectedBonds(beg);
                    if (bonds.Count() == 0)
                    {
                        continue; // bad
                    }
                    sgroup.Add(beg);
                    sgroup.Add(bonds.First());
                    foreach (var endpt in e.Value)
                    {
                        sgroup.Add(atoms[endpt]);
                    }
                    sgroupMap.Add(mol, sgroup);
                }
            }

            // data sgroups
            if (cxstate.dataSgroups != null)
            {
                foreach (var dsgroup in cxstate.dataSgroups)
                {
                    if (dsgroup.Field != null && dsgroup.Field.StartsWith("cdk:", StringComparison.Ordinal))
                    {
                        chemObj.SetProperty(dsgroup.Field, dsgroup.Value);
                    }
                }
            }

            // polymer Sgroups
            if (cxstate.sgroups != null)
            {
                foreach (var psgroup in cxstate.sgroups)
                {
                    var            sgroup  = new Sgroup();
                    var            atomset = new HashSet <IAtom>();
                    IAtomContainer mol     = null;
                    foreach (var idx in psgroup.AtomSet)
                    {
                        if (idx >= atoms.Count)
                        {
                            continue;
                        }
                        var atom = atoms[idx];
                        var amol = atomToMol[atom];

                        if (mol == null)
                        {
                            mol = amol;
                        }
                        else if (amol != mol)
                        {
                            goto C_PolySgroup;
                        }

                        atomset.Add(atom);
                    }

                    if (mol == null)
                    {
                        continue;
                    }

                    foreach (var atom in atomset)
                    {
                        foreach (var bond in mol.GetConnectedBonds(atom))
                        {
                            if (!atomset.Contains(bond.GetOther(atom)))
                            {
                                sgroup.Add(bond);
                            }
                        }
                        sgroup.Add(atom);
                    }

                    sgroup.Subscript = psgroup.Subscript;
                    sgroup.PutValue(SgroupKey.CtabConnectivity, psgroup.Supscript);

                    switch (psgroup.Type)
                    {
                    case "n":
                        sgroup.Type = SgroupType.CtabStructureRepeatUnit;
                        break;

                    case "mon":
                        sgroup.Type = SgroupType.CtabMonomer;
                        break;

                    case "mer":
                        sgroup.Type = SgroupType.CtabMer;
                        break;

                    case "co":
                        sgroup.Type = SgroupType.CtabCopolymer;
                        break;

                    case "xl":
                        sgroup.Type = SgroupType.CtabCrossLink;
                        break;

                    case "mod":
                        sgroup.Type = SgroupType.CtabModified;
                        break;

                    case "mix":
                        sgroup.Type = SgroupType.CtabMixture;
                        break;

                    case "f":
                        sgroup.Type = SgroupType.CtabFormulation;
                        break;

                    case "any":
                        sgroup.Type = SgroupType.CtabAnyPolymer;
                        break;

                    case "gen":
                        sgroup.Type = SgroupType.CtabGeneric;
                        break;

                    case "c":
                        sgroup.Type = SgroupType.CtabComponent;
                        break;

                    case "grf":
                        sgroup.Type = SgroupType.CtabGraft;
                        break;

                    case "alt":
                        sgroup.Type = SgroupType.CtabCopolymer;
                        sgroup.PutValue(SgroupKey.CtabSubType, "ALT");
                        break;

                    case "ran":
                        sgroup.Type = SgroupType.CtabCopolymer;
                        sgroup.PutValue(SgroupKey.CtabSubType, "RAN");
                        break;

                    case "blk":
                        sgroup.Type = SgroupType.CtabCopolymer;
                        sgroup.PutValue(SgroupKey.CtabSubType, "BLO");
                        break;
                    }
                    sgroupMap.Add(mol, sgroup);
C_PolySgroup:
                    ;
                }
            }

            // assign Sgroups
            foreach (var e in sgroupMap)
            {
                e.Key.SetCtabSgroups(new List <Sgroup>(e.Value));
            }
        }
示例#23
0
        /// <summary>
        /// Copy a collection of Sgroups, replacing any <see cref="IAtom"/>/<see cref="IBond"/>
        /// references with those present in the provided 'replace' map. If an empty
        /// replace map is provided (null or empty) the sgroups are simply
        /// duplicated. If an item is not present in the replacement map the original
        /// item is preserved.
        /// </summary>
        /// <example>
        /// <code>
        /// var replace = new Dictionary&lt;Sgroup, Sgroup&gt;();
        /// replace[orgAtom] = newAtom;
        /// replace[orgBond] = newBond;
        /// newSgroups = Copy(orgSgroups, replace);
        /// </code>
        /// </example>
        /// <param name="sgroups">collection of sgroups, can be null</param>
        /// <param name="replace">the replacement map, can be null</param>
        /// <returns>list of copied sgroups, null if sgroups input was null</returns>
        public static IList <Sgroup> Copy(IList <Sgroup> sgroups, CDKObjectMap replace)
        {
            if (sgroups == null)
            {
                return(null);
            }
            var sgroupMap = new Dictionary <Sgroup, Sgroup>();

            foreach (var sgroup in sgroups)
            {
                sgroupMap[sgroup] = new Sgroup();
            }
            foreach (var e in sgroupMap)
            {
                var orgSgroup = e.Key;
                var cpySgroup = e.Value;
                cpySgroup.Type = orgSgroup.Type;
                foreach (var atom in orgSgroup.Atoms)
                {
                    cpySgroup.Atoms.Add(Get(replace, atom));
                }
                foreach (var bond in orgSgroup.Bonds)
                {
                    cpySgroup.Bonds.Add(Get(replace, bond));
                }
                foreach (var parent in orgSgroup.Parents)
                {
                    cpySgroup.Parents.Add(sgroupMap[parent]);
                }
                foreach (var key in SgroupTool.SgroupKeyValues)
                {
                    switch (key)
                    {
                    case SgroupKey.CtabParentAtomList:
                    {
                        var orgVal = (ICollection <IAtom>)orgSgroup.GetValue(key);
                        if (orgVal != null)
                        {
                            var cpyVal = new List <IAtom>();
                            foreach (IAtom atom in orgVal)
                            {
                                cpyVal.Add(Get(replace, atom));
                            }
                            cpySgroup.PutValue(key, cpyVal);
                        }
                    }
                    break;

                    case SgroupKey.CtabBracket:
                    {
                        var orgVals = (ICollection <SgroupBracket>)orgSgroup.GetValue(key);
                        if (orgVals != null)
                        {
                            foreach (var bracket in orgVals)
                            {
                                cpySgroup.AddBracket(new SgroupBracket(bracket));
                            }
                        }
                    }
                    break;

                    default:
                        // primitive values, String, Integer are immutable
                        object val = orgSgroup.GetValue(key);
                        if (val != null)
                        {
                            cpySgroup.PutValue(key, val);
                        }
                        break;
                    }
                }
            }
            return(new List <Sgroup>(sgroupMap.Values));
        }