Example #1
0
        public AtomSymbol GenerateAbbreviatedSymbol(string label, HydrogenPosition position)
        {
            var tokens = new List <string>();

            if (AbbreviationLabel.Parse(label, tokens))
            {
                return(GenerateAbbreviationSymbol(tokens, position));
            }
            else
            {
                return(new AtomSymbol(new TextOutline(label, font, emSize), Array.Empty <TextOutline>()));
            }
        }
Example #2
0
        /// <summary>
        /// Generate the displayed atom symbol for an atom in given structure with the specified hydrogen
        /// position.
        /// </summary>
        /// <param name="container">structure to which the atom belongs</param>
        /// <param name="atom">the atom to generate the symbol for</param>
        /// <param name="position">the hydrogen position</param>
        /// <param name="model">additional rendering options</param>
        /// <returns>atom symbol</returns>
        public AtomSymbol GenerateSymbol(IAtomContainer container, IAtom atom, HydrogenPosition position, RendererModel model)
        {
            if (atom is IPseudoAtom pAtom)
            {
                if (pAtom.AttachPointNum <= 0)
                {
                    if ("*".Equals(pAtom.Label, StringComparison.Ordinal))
                    {
                        var mass   = pAtom.MassNumber ?? 0;
                        var charge = pAtom.FormalCharge ?? 0;
                        var hcnt   = pAtom.ImplicitHydrogenCount ?? 0;
                        var nrad   = container.GetConnectedSingleElectrons(atom).Count();
                        if (mass != 0 || charge != 0 || hcnt != 0)
                        {
                            return(GeneratePeriodicSymbol(0, hcnt, mass, charge, nrad, position));
                        }
                    }
                    return(GeneratePseudoSymbol(AccessPseudoLabel(pAtom, "?"), position));
                }
                else
                {
                    return(null); // attach point drawn in bond generator
                }
            }
            else
            {
                var number = atom.AtomicNumber;

                // unset the mass if it's the major isotope (could be an option)
                var mass = atom.MassNumber;
                if (number != 0 &&
                    mass != null &&
                    model != null &&
                    model.GetOmitMajorIsotopes() &&
                    IsMajorIsotope(number, mass.Value))
                {
                    mass = null;
                }

                return(GeneratePeriodicSymbol(
                           number,
                           atom.ImplicitHydrogenCount ?? 0,
                           mass ?? -1,
                           atom.FormalCharge ?? 0,
                           container.GetConnectedSingleElectrons(atom).Count(), position));
            }
        }
Example #3
0
        /// <summary>
        /// Position the hydrogen label relative to the element label.
        /// </summary>
        /// <param name="position">relative position where the hydrogen is placed</param>
        /// <param name="element">the outline of the element label</param>
        /// <param name="hydrogen">the outline of the hydrogen</param>
        /// <returns>positioned hydrogen label</returns>
        public TextOutline PositionHydrogenLabel(HydrogenPosition position, TextOutline element, TextOutline hydrogen)
        {
            var elementBounds  = element.GetBounds();
            var hydrogenBounds = hydrogen.GetBounds();

            switch (position)
            {
            case HydrogenPosition.Above:
                return(hydrogen.Translate(0, (elementBounds.Top - padding) - hydrogenBounds.Bottom));

            case HydrogenPosition.Right:
                return(hydrogen.Translate((elementBounds.Right + padding) - hydrogenBounds.Left, 0));

            case HydrogenPosition.Below:
                return(hydrogen.Translate(0, (elementBounds.Bottom + padding) - hydrogenBounds.Top));

            case HydrogenPosition.Left:
                return(hydrogen.Translate((elementBounds.Left - padding) - hydrogenBounds.Right, 0));
            }
            return(hydrogen); // never reached
        }
Example #4
0
        /// <summary>
        /// Position the charge label on the top right of either the element or hydrogen label. Where the
        /// charge is placed depends on the number of hydrogens and their position relative to the
        /// element symbol.
        /// </summary>
        /// <param name="hydrogens">number of hydrogen</param>
        /// <param name="position">position of hydrogen</param>
        /// <param name="charge">the charge label outline (to be positioned)</param>
        /// <param name="element">the element label outline</param>
        /// <param name="hydrogen">the hydrogen label outline</param>
        /// <returns>positioned charge label</returns>
        public TextOutline PositionChargeLabel(int hydrogens, HydrogenPosition position, TextOutline charge, TextOutline element, TextOutline hydrogen)
        {
            var chargeBounds = charge.GetBounds();

            // the charge is placed to the top right of the element symbol
            // unless either the hydrogen label or the hydrogen count label
            // are in the way - in which case we place it relative to the
            // hydrogen
            var referenceBounds = element.GetBounds();

            if (hydrogens > 0 && position == HydrogenPosition.Right)
            {
                referenceBounds = hydrogen.GetBounds();
            }
            else if (hydrogens > 1 && position == HydrogenPosition.Above)
            {
                referenceBounds = hydrogen.GetBounds();
            }

            return(charge.Translate((referenceBounds.Right + padding) - chargeBounds.Left,
                                    (referenceBounds.Top - (chargeBounds.Height / 2)) - chargeBounds.Top));
        }
Example #5
0
 public static string Name(this HydrogenPosition value)
 => names[(int)value];
Example #6
0
 /// <summary>
 /// The directional vector for this hydrogen position.
 /// </summary>
 public static Vector2 Vector(this HydrogenPosition value)
 => V[(int)value].Vector;
Example #7
0
        /// <summary>
        /// Generate an atom symbol for a periodic element with the specified number of hydrogens, ionic
        /// charge, mass,
        /// </summary>
        /// <param name="number">atomic number</param>
        /// <param name="hydrogens">labelled hydrogen count</param>
        /// <param name="mass">atomic mass</param>
        /// <param name="charge">ionic formal charge</param>
        /// <param name="unpaired">number of unpaired electrons</param>
        /// <param name="position">placement of hydrogen</param>
        /// <returns>laid out atom symbol</returns>
        public AtomSymbol GeneratePeriodicSymbol(int number, int hydrogens, int mass, int charge, int unpaired, HydrogenPosition position)
        {
            var element = number == 0
                        ? new TextOutline("*", font, emSize)
                        : new TextOutline(ChemicalElement.Of(number).Symbol, font, emSize);
            var hydrogenAdjunct = defaultHydrogenLabel;

            // the hydrogen count, charge, and mass adjuncts are script size
            var hydrogenCount = new TextOutline(hydrogens.ToString(), font, emSize).Resize(scriptSize, scriptSize);
            var chargeAdjunct = new TextOutline(ChargeAdjunctText(charge, unpaired), font, emSize).Resize(scriptSize, scriptSize);
            var massAdjunct   = new TextOutline(mass.ToString(), font, emSize).Resize(scriptSize, scriptSize);

            // position each adjunct relative to the element label and each other
            hydrogenAdjunct = PositionHydrogenLabel(position, element, hydrogenAdjunct);
            hydrogenCount   = PositionSubscript(hydrogenAdjunct, hydrogenCount);
            chargeAdjunct   = PositionChargeLabel(hydrogens, position, chargeAdjunct, element, hydrogenAdjunct);
            massAdjunct     = PositionMassLabel(massAdjunct, element);

            // when the hydrogen label is positioned to the left we may need to nudge it
            // over to account for the hydrogen count and/or the mass adjunct colliding
            // with the element label
            if (position == HydrogenPosition.Left)
            {
                var nudgeX = HydrogenXDodge(hydrogens, mass, element, hydrogenAdjunct, hydrogenCount, massAdjunct);
                hydrogenAdjunct = hydrogenAdjunct.Translate(nudgeX, 0);
                hydrogenCount   = hydrogenCount.Translate(nudgeX, 0);
            }

            var adjuncts = new List <TextOutline>(4);

            if (hydrogens > 0)
            {
                adjuncts.Add(hydrogenAdjunct);
            }
            if (hydrogens > 1)
            {
                adjuncts.Add(hydrogenCount);
            }
            if (charge != 0 || unpaired > 0)
            {
                adjuncts.Add(chargeAdjunct);
            }
            if (mass > 0)
            {
                adjuncts.Add(massAdjunct);
            }

            return(new AtomSymbol(element, adjuncts));
        }
Example #8
0
        /// <summary>
        /// Generate a formatted abbreviation AtomSymbol for the given Hydrogen position.
        /// </summary>
        /// <param name="tokens">the parsed tokens</param>
        /// <param name="position">hydrogen position - determines if we reverse the label</param>
        /// <returns>the generated symbol</returns>
        public AtomSymbol GenerateAbbreviationSymbol(List <string> tokens, HydrogenPosition position)
        {
            if (position == HydrogenPosition.Left)
            {
                AbbreviationLabel.Reverse(tokens);
            }

            var tmpRefPoint = new TextOutline("H", font, emSize);
            var fTexts      = AbbreviationLabel.Format(tokens);

            var italicFont = new Typeface(font.FontFamily, FontStyles.Italic, font.Weight, font.Stretch);

            var outlines = new List <TextOutline>(fTexts.Count);

            foreach (var fText in fTexts)
            {
                var outline = fText.Style == AbbreviationLabel.STYLE_ITALIC
                            ? new TextOutline(fText.Text, italicFont, emSize)
                            : new TextOutline(fText.Text, font, emSize);

                // resize and position scripts
                if (fText.Style == AbbreviationLabel.STYLE_SUBSCRIPT)
                {
                    outline = outline.Resize(scriptSize, scriptSize);
                    outline = PositionSubscript(tmpRefPoint, outline);
                }
                else if (fText.Style == AbbreviationLabel.STYLE_SUPSCRIPT)
                {
                    outline = outline.Resize(scriptSize, scriptSize);
                    outline = PositionSuperscript(tmpRefPoint, outline);
                }

                outlines.Add(outline);
            }

            // position the outlines relative to each other
            for (int i = 1; i < outlines.Count; i++)
            {
                var ref_ = outlines[i - 1];
                var curr = outlines[i];
                // charge aligns to symbol not a subscript part
                if (fTexts[i].Style == AbbreviationLabel.STYLE_SUPSCRIPT &&
                    fTexts[i - 1].Style == AbbreviationLabel.STYLE_SUBSCRIPT && i > 1)
                {
                    ref_ = outlines[i - 2];
                }
                outlines[i] = PositionAfter(ref_, curr);
            }

            // find symbol where we want to attach the bond
            // this becomes the primary outline
            int index;

            if (position == HydrogenPosition.Left)
            {
                for (index = outlines.Count - 1; index >= 0; index--)
                {
                    if ((fTexts[index].Style & 0x1) == 0)
                    {
                        break;
                    }
                }
            }
            else
            {
                for (index = 0; index < outlines.Count; index++)
                {
                    if ((fTexts[index].Style & 0x1) == 0)
                    {
                        break;
                    }
                }
            }
            var primary = outlines[index];

            outlines.RemoveAt(index);

            return(new AtomSymbol(primary, outlines));
        }
Example #9
0
        /// <summary>
        /// Generates an atom symbol for a pseudo atom.
        /// </summary>
        /// <returns>the atom symbol</returns>
        public AtomSymbol GeneratePseudoSymbol(string label, HydrogenPosition position)
        {
            var italicFont = new Typeface(font.FontFamily, FontStyles.Italic, FontWeights.Bold, font.Stretch);
            var outlines   = new List <TextOutline>(3);

            int beg = 0;
            int pos = 0;
            int len = label.Length;

            // upper case followed by lower case
            while (pos < len && IsUpperCase(label[pos]))
            {
                pos++;
            }
            if (label[0] != 'R') // Ar is not A^r but 'Ra' is R^a etc
            {
                while (pos < len && IsLowerCase(label[pos]))
                {
                    pos++;
                }
            }

            if (pos > beg)
            {
                outlines.Add(new TextOutline(label.Substring(beg, pos), italicFont, emSize));
                beg = pos;
                // 2a etc.
                while (pos < len && IsDigit(label[pos]))
                {
                    pos++;
                }
                while (pos < len && IsLowerCase(label[pos]))
                {
                    pos++;
                }

                if (pos > beg)
                {
                    var outline = new TextOutline(label.Substring(beg, pos - beg), italicFont, emSize);
                    outline = outline.Resize(scriptSize, scriptSize);
                    outline = PositionSuperscript(outlines[0], outline);
                    outlines.Add(outline);
                }

                int numPrimes = 0;

                while (pos < len)
                {
                    switch (label[pos])
                    {
                    case '\'': numPrimes++; break;

                    case '`': numPrimes++; break;

                    case '‘': numPrimes++; break;

                    case '’': numPrimes++; break;

                    case '‛': numPrimes++; break;

                    case '“': numPrimes += 2; break;

                    case '”': numPrimes += 2; break;

                    case '′': numPrimes++; break;

                    case '″': numPrimes += 2; break;

                    case '‴': numPrimes += 3; break;

                    case '⁗': numPrimes += 4; break;

                    case '‵': numPrimes++; break;

                    case '‶': numPrimes += 2; break;

                    case '‷': numPrimes += 3; break;

                    case '´': numPrimes++; break;

                    case 'ˊ': numPrimes++; break;

                    case '́': numPrimes++; break;

                    case '˝': numPrimes += 2; break;

                    case '̋': numPrimes += 2; break;

                    default:
                        goto break_PRIMES;
                    }
                    pos++;
                }
break_PRIMES:
                if (pos < len)
                {
                    return(new AtomSymbol(
                               new TextOutline(label, italicFont, emSize),
                               Array.Empty <TextOutline>()));
                }
                else
                {
                    TextOutline outline = null;
                    var         ref_    = outlines[outlines.Count - 1];
                    switch (numPrimes)
                    {
                    case 0: break;

                    case 1: outline = new TextOutline("′", font, emSize); break;

                    case 2: outline = new TextOutline("″", font, emSize); break;

                    case 3: outline = new TextOutline("‴", font, emSize); break;

                    default:
                        string lab = "";
                        while (numPrimes-- > 0)
                        {
                            lab += "′";
                        }
                        outline = new TextOutline(lab, font, emSize);
                        break;
                    }
                    if (outline != null)
                    {
                        if (outlines.Count > 1)
                        {
                            outline = outline.Resize(scriptSize, scriptSize);
                        }
                        outline = PositionSuperscript(ref_, outline);
                        outlines.Add(outline);
                    }
                }

                // line up text
                for (int i = 1; i < outlines.Count; i++)
                {
                    var ref_ = outlines[i - 1];
                    var curr = outlines[i];
                    outlines[i] = PositionAfter(ref_, curr);
                }

                return(new AtomSymbol(outlines[0], outlines.GetRange(1, outlines.Count - 1)));
            }
            else
            {
                return(new AtomSymbol(new TextOutline(label, italicFont, emSize), Array.Empty <TextOutline>()));
            }
        }