/// <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); } }
/// <summary> /// If the molecule has display shortcuts (abbreviations or multiple group sgroups) certain parts /// of the structure are hidden from display. This method marks the parts to hide and in the case /// of abbreviations, remaps atom symbols. Apart from additional property flags, the molecule /// is unchanged by this method. /// </summary> /// <param name="container">molecule input</param> /// <param name="symbolRemap">a map that will hold symbol remapping</param> public static void PrepareDisplayShortcuts(IAtomContainer container, IDictionary <IAtom, string> symbolRemap) { var sgroups = container.GetCtabSgroups(); if (sgroups == null || !sgroups.Any()) { return; } // select abbreviations that should be contracted foreach (var sgroup in sgroups) { if (sgroup.Type == SgroupType.CtabAbbreviation) { bool?expansion = (bool?)sgroup.GetValue(SgroupKey.CtabExpansion); // abbreviation is displayed as expanded if (expansion ?? false) { continue; } // no or empty label, skip it if (string.IsNullOrEmpty(sgroup.Subscript)) { continue; } // only contract if the atoms are either partially or fully highlighted if (CheckAbbreviationHighlight(container, sgroup)) { ContractAbbreviation(container, symbolRemap, sgroup); } } else if (sgroup.Type == SgroupType.CtabMultipleGroup) { HideMultipleParts(container, sgroup); } else if (sgroup.Type == SgroupType.ExtMulticenter) { var atoms = sgroup.Atoms; // should only be one bond foreach (var bond in sgroup.Bonds) { var beg = bond.Begin; var end = bond.End; if (atoms.Contains(beg)) { StandardGenerator.HideFully(beg); } else { StandardGenerator.HideFully(end); } } } } }
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)); } }
/// <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; } } }
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)); } }
private TextOutline MakeText(string subscriptSuffix, Vector2 b1p2, Vector2 b1pvec, double labelScale) { return(StandardGenerator.GenerateAnnotation(b1p2, subscriptSuffix, VecmathUtil.Negate(b1pvec), 1, labelScale, font, emSize, null).Resize(1 / scale, 1 / scale)); }