public void AlignToRight() { TextOutline outline = new TextOutline("Cl", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, Array.Empty <TextOutline>()); AssertCloseTo(outline.GetLastGlyphCenter(), symbol.AlignTo(Right).GetAlignmentCenter(), 0.01); }
/// <summary> /// Generate an annotation 'label' for an atom (located at 'basePoint'). The label is offset from /// the basePoint by the provided 'distance' and 'direction'. /// </summary> /// <param name="basePoint">the relative (0,0) reference</param> /// <param name="label">the annotation text</param> /// <param name="direction">the direction along which the label is laid out</param> /// <param name="distance">the distance along the direct to travel</param> /// <param name="scale">the font scale of the label</param> /// <param name="font">the font to use</param> /// <param name="symbol">the atom symbol to avoid overlap with</param> /// <returns>the position text outline for the annotation</returns> internal static TextOutline GenerateAnnotation(Vector2 basePoint, string label, Vector2 direction, double distance, double scale, Typeface font, double emSize, AtomSymbol symbol) { var italicHint = label.StartsWith(ItalicDisplayPrefix); label = italicHint ? label.Substring(ItalicDisplayPrefix.Length) : label; var annFont = italicHint ? new Typeface(font.FontFamily, WPF.FontStyles.Italic, font.Weight, font.Stretch) : font; var annOutline = new TextOutline(label, annFont, emSize).Resize(scale, -scale); // align to the first or last character of the annotation depending on the direction var center = direction.X > 0.3 ? annOutline.GetFirstGlyphCenter() : direction.X < -0.3 ? annOutline.GetLastGlyphCenter() : annOutline.GetCenter(); // Avoid atom symbol if (symbol != null) { var intersect = symbol.GetConvexHull().Intersect(VecmathUtil.ToPoint(basePoint), VecmathUtil.ToPoint(VecmathUtil.Sum(basePoint, direction))); // intersect should never be null be check against this if (intersect != null) { basePoint = VecmathUtil.ToVector(intersect); } } direction *= distance; direction += basePoint; // move to position return(annOutline.Translate(direction.X - center.X, direction.Y - center.Y)); }
private static TextOutline LeftAlign(TextOutline outline) { var center = outline.GetCenter(); var first = outline.GetFirstGlyphCenter(); return(outline.Translate(center.X - first.X, center.Y - first.Y)); }
[TestMethod()] // Font bounds vary between systems public void UntransformedCenter() { TextOutline clOutline = new TextOutline("Cl", font, emSize); var center = clOutline.GetCenter(); Assert.AreEqual(5.62, center.X, 0.01); Assert.AreEqual(-4.47, center.Y, 0.01); }
public void TestGetLastGlyphCenter() { TextOutline original = new TextOutline("Cl", font, emSize); var oCenter = original.GetCenter(); var tCenter = original.GetLastGlyphCenter(); Assert.IsTrue(tCenter.X > oCenter.X); }
/// <summary> /// Internal constructor with required attributes. /// </summary> /// <param name="font">the font to depict symbols with</param> /// <param name="adjunctSpacing">the spacing between adjuncts and the element symbol as fraction of 'H' width</param> /// <param name="scriptSize">the size of</param> private StandardAtomGenerator(Typeface font, double emSize, double adjunctSpacing, double scriptSize) { this.font = font; this.emSize = emSize; this.scriptSize = scriptSize; this.defaultHydrogenLabel = new TextOutline("H", font, emSize); this.padding = adjunctSpacing * defaultHydrogenLabel.GetBounds().Width; }
/// <summary> /// Position the mass label relative to the element label. The mass adjunct is position to the /// top left of the element label. /// </summary> /// <param name="massLabel">mass label outline</param> /// <param name="elementLabel">element label outline</param> /// <returns>positioned mass label</returns> public TextOutline PositionMassLabel(TextOutline massLabel, TextOutline elementLabel) { var elementBounds = elementLabel.GetBounds(); var massBounds = massLabel.GetBounds(); return(massLabel.Translate((elementBounds.Left - padding) - massBounds.Right, (elementBounds.Top - (massBounds.Height / 2)) - massBounds.Top)); }
public TextOutline PositionAfter(TextOutline before, TextOutline after) { var fixedBounds = before.GetBounds(); var movableBounds = after.GetBounds(); after = after.Translate((fixedBounds.Right + padding) - movableBounds.Left, 0); return(after); }
/// <summary> /// Internal constructor provides the attributes. /// </summary> /// <param name="element">the element label</param> /// <param name="adjuncts">the adjunct labels</param> /// <param name="alignment">left, center, or right alignment</param> /// <param name="hull">convex hull</param> private AtomSymbol(TextOutline element, IList <TextOutline> adjuncts, IList <TextOutline> annotationAdjuncts, SymbolAlignment alignment, ConvexHull hull) { this.element = element; this.adjuncts = adjuncts; this.annotationAdjuncts = annotationAdjuncts; this.alignment = alignment; this.hull = hull; }
/// <summary> /// Create a new atom symbol with the specified adjuncts. /// </summary> /// <param name="element">the element symbol (e.g. 'N' in 'NH4+')</param> /// <param name="adjuncts">the adjuncts</param> public AtomSymbol(TextOutline element, IList <TextOutline> adjuncts) { this.element = element; this.adjuncts = adjuncts; this.annotationAdjuncts = new List <TextOutline>(); this.alignment = SymbolAlignment.Center; this.hull = ConvexHull.OfShapes(GetOutlines()); }
public void FirstAndLastCenterIsTheSameForSingleLetterOutline() { TextOutline oOutline = new TextOutline("O", font, emSize); var firstCenter = oOutline.GetFirstGlyphCenter(); var lastCenter = oOutline.GetLastGlyphCenter(); Assert.AreEqual(lastCenter.X, firstCenter.X, 0.01); Assert.AreEqual(lastCenter.Y, firstCenter.Y, 0.01); }
public void ResizeMaintainsCenter() { TextOutline clOutline = new TextOutline("Cl", font, emSize); var orgCenter = clOutline.GetCenter(); var newCenter = clOutline.Resize(21, 5).GetCenter(); Assert.AreEqual(newCenter.X, orgCenter.X, 0.01); Assert.AreEqual(newCenter.Y, orgCenter.Y, 0.01); }
public TextOutline PositionSuperscript(TextOutline label, TextOutline superscript) { var labelBounds = label.GetBounds(); var superscriptBounds = superscript.GetBounds(); superscript = superscript.Translate((labelBounds.Right + padding) - superscriptBounds.Left, (labelBounds.Top - (superscriptBounds.Height / 2)) - superscriptBounds.Top); return(superscript); }
/// <summary> /// Positions an outline in the subscript position relative to another 'primary' label. /// </summary> /// <param name="label">a label outline</param> /// <param name="subscript">the label outline to position as subscript</param> /// <returns>positioned subscript outline</returns> public TextOutline PositionSubscript(TextOutline label, TextOutline subscript) { var hydrogenBounds = label.GetBounds(); var hydrogenCountBounds = subscript.GetBounds(); subscript = subscript.Translate((hydrogenBounds.Right + padding) - hydrogenCountBounds.Left, (hydrogenBounds.Bottom + (hydrogenCountBounds.Height / 2)) - hydrogenCountBounds.Bottom); return(subscript); }
/// <summary> /// Include a new annotation adjunct in the atom symbol. /// </summary> /// <param name="annotation">the new annotation adjunct</param> /// <returns>a new AtomSymbol instance including the annotation adjunct</returns> public AtomSymbol AddAnnotation(TextOutline annotation) { List <TextOutline> newAnnotations = new List <TextOutline>(annotationAdjuncts) { annotation }; return(new AtomSymbol(element, adjuncts, newAnnotations, alignment, hull)); }
public void TransformedCenter() { TextOutline original = new TextOutline("Cl", font, emSize); TextOutline transformed = original.Translate(0, -5); var oCenter = original.GetCenter(); var tCenter = transformed.GetCenter(); Assert.AreEqual(oCenter.X, tCenter.X, 0.01); Assert.AreEqual(oCenter.Y - 5, tCenter.Y, 0.01); }
public void TestToString() { TextOutline outline = new TextOutline("Cl", font, emSize); var bounds = outline.GetBounds(); Assert.AreEqual( "Cl [x=" + ToString(bounds.X) + ", y=" + ToString(bounds.Y) + ", w=" + ToString(bounds.Width) + ", h=" + ToString(bounds.Height) + "]", outline.ToString()); }
[TestMethod(), Ignore()] // Font bounds vary between systems public void UntransformedBounds() { TextOutline clOutline = new TextOutline("Cl", font, emSize); var bounds = clOutline.GetBounds(); Assert.AreEqual(0.67, bounds.X, 0.01); Assert.AreEqual(-9.12, bounds.Y, 0.01); Assert.AreEqual(9.90, bounds.Width, 0.01); Assert.AreEqual(9.28, bounds.Height, 0.01); }
public void PositionMassLabel() { var mass = new TextOutline("15", font, emSize); var positioned = atomGenerator.PositionMassLabel(mass, element); var elementBounds = element.GetBounds(); var massBounds = positioned.GetBounds(); Assert.IsTrue(massBounds.Right < elementBounds.Left); Assert.AreEqual(elementBounds.Top, massBounds.CenterY(), 0.01); }
public void PositionHydrogenCount() { var hydrogenCount = new TextOutline("2", font, emSize); var positioned = atomGenerator.PositionSubscript(hydrogen, hydrogenCount); var hydrogenBounds = hydrogen.GetBounds(); var hydrogenCountBounds = positioned.GetBounds(); Assert.IsTrue(hydrogenCountBounds.Left > hydrogenBounds.Left); Assert.AreEqual(hydrogenBounds.Bottom, hydrogenCountBounds.CenterY(), 0.01); }
public void BoundsTransformedWithYTranslation() { TextOutline original = new TextOutline("Cl", font, emSize); TextOutline transformed = original.Translate(0, -5); var oBounds = original.GetBounds(); var tBounds = transformed.GetBounds(); Assert.AreEqual(oBounds.X, tBounds.X, 0.01); Assert.AreEqual(oBounds.Y - 5, tBounds.Y, 0.01); Assert.AreEqual(oBounds.Width, tBounds.Width, 0.01); Assert.AreEqual(oBounds.Height, tBounds.Height, 0.01); }
public void TestGetOutlines() { TextOutline outline = new TextOutline("Cl", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, Array.Empty <TextOutline>()); var outlineBounds = outline.GetOutline().Bounds; var symbolBounds = symbol.GetOutlines()[0].Bounds; Assert.AreEqual(symbolBounds.X, outlineBounds.X, 0.01); Assert.AreEqual(symbolBounds.Y, outlineBounds.Y, 0.01); Assert.AreEqual(symbolBounds.Left, outlineBounds.Left, 0.01); Assert.AreEqual(symbolBounds.Bottom, outlineBounds.Bottom, 0.01); }
public void PositionOfChargeWhenHydrogensAreBelow() { var charge = new TextOutline("+", font, emSize); var positioned = atomGenerator.PositionChargeLabel(1, HydrogenPosition.Below, charge, element, hydrogen.Translate(0, 5)); var elementBounds = element.GetBounds(); var chargeBounds = positioned.GetBounds(); Assert.IsTrue(chargeBounds.Left > elementBounds.Left); Assert.AreEqual(elementBounds.Top, chargeBounds.CenterY(), 0.01); }
public void ResizeModifiesBounds() { TextOutline original = new TextOutline("Cl", font, emSize); TextOutline transformed = original.Resize(2, 2); var oBounds = original.GetBounds(); var tBounds = transformed.GetBounds(); Assert.AreEqual(oBounds.X - oBounds.Width / 2, tBounds.X, 0.01); Assert.AreEqual(oBounds.Y - oBounds.Height / 2, tBounds.Y, 0.01); Assert.AreEqual(oBounds.Width * 2, tBounds.Width, 0.01); Assert.AreEqual(oBounds.Height * 2, tBounds.Height, 0.01); }
public void TestGetOutlinesWithAdjunct() { TextOutline outline = new TextOutline("Cl", font, emSize); TextOutline adjunct = new TextOutline("H", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, new[] { adjunct }); var outlineBounds = adjunct.GetOutline().Bounds; var symbolBounds = symbol.GetOutlines()[1].Bounds; Assert.AreEqual(symbolBounds.X, outlineBounds.X, 0.01); Assert.AreEqual(symbolBounds.Y, outlineBounds.Y, 0.01); Assert.AreEqual(symbolBounds.Left, outlineBounds.Left, 0.01); Assert.AreEqual(symbolBounds.Bottom, outlineBounds.Bottom, 0.01); }
public void TestTranslate() { TextOutline outline = new TextOutline("Cl", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, Array.Empty <TextOutline>()); AtomSymbol transformed = symbol.Translate(4, 2); var orgBounds = symbol.GetOutlines()[0].Bounds; var newBounds = transformed.GetOutlines()[0].Bounds; Assert.AreEqual(orgBounds.X + 4, newBounds.X, 0.01); Assert.AreEqual(orgBounds.Y + 2, newBounds.Y, 0.01); Assert.AreEqual(orgBounds.Right + 4, newBounds.Right, 0.01); Assert.AreEqual(orgBounds.Bottom + 2, newBounds.Bottom, 0.01); }
public void TestResize() { TextOutline outline = new TextOutline("Cl", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, Array.Empty <TextOutline>()); AtomSymbol transformed = symbol.Resize(2, 2); var orgBounds = outline.GetBounds(); var newBounds = transformed.GetOutlines()[0].Bounds; Assert.AreEqual(orgBounds.Left - orgBounds.Width / 2, newBounds.Left, 0.01); Assert.AreEqual(orgBounds.Top - orgBounds.Height / 2, newBounds.Top, 0.01); Assert.AreEqual(orgBounds.Right + orgBounds.Width / 2, newBounds.Right, 0.01); Assert.AreEqual(orgBounds.Bottom + orgBounds.Height / 2, newBounds.Bottom, 0.01); }
public void PositionOfChargeWhenOneHydrogenIsAbove() { // hydrogen is arbitrarily moved to ensure x/y are different from the element var charge = new TextOutline("+", font, emSize); var localHydrogen = hydrogen.Translate(10, 10); var positioned = atomGenerator.PositionChargeLabel(1, HydrogenPosition.Above, charge, element, localHydrogen); var elementBounds = element.GetBounds(); var chargeBounds = positioned.GetBounds(); Assert.IsTrue(chargeBounds.Left > elementBounds.Left); Assert.AreEqual(elementBounds.Top, chargeBounds.CenterY(), 0.01); }
/// <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)); }
public void TestGetConvexHull() { TextOutline outline = new TextOutline("Cl", font, emSize); AtomSymbol symbol = new AtomSymbol(outline, Array.Empty <TextOutline>()); ConvexHull outlineHull = ConvexHull.OfShape(outline.GetOutline()); ConvexHull symbolHull = symbol.GetConvexHull(); var outlineBounds = outlineHull.Outline.Bounds; var symbolBounds = symbolHull.Outline.Bounds; Assert.AreEqual(symbolBounds.X, outlineBounds.X, 0.01); Assert.AreEqual(symbolBounds.Y, outlineBounds.Y, 0.01); Assert.AreEqual(symbolBounds.Left, outlineBounds.Left, 0.01); Assert.AreEqual(symbolBounds.Bottom, outlineBounds.Bottom, 0.01); }