public void PlaceString(string text, Point startPoint, string path) { Point cursor = new Point(startPoint.X, startPoint.Y); TtfCharacter i = _TtfCharacterSet['i']; for (int idx = 0; idx < text.Length; idx++) { TtfCharacter c = _TtfCharacterSet['?']; char chr = text[idx]; if (_TtfCharacterSet.ContainsKey(chr)) { c = _TtfCharacterSet[chr]; } if (c != null) { Point position = GetCharacterPosition(cursor, c); AtomLabelCharacter alc = new AtomLabelCharacter(position, c, "000000", chr, path, path); _AtomLabelCharacters.Add(alc); if (idx < text.Length - 1) { // Move to next Character position cursor.Offset(OoXmlHelper.ScaleCsTtfToCml(c.Width + i.Width, _meanBondLength), 0); } } } }
public void DrawCharacter(Wpg.WordprocessingGroup wordprocessingGroup, AtomLabelCharacter alc) { Point characterPosition = new Point(alc.Position.X, alc.Position.Y); characterPosition.Offset(-_canvasExtents.Left, -_canvasExtents.Top); UInt32Value id = UInt32Value.FromUInt32((uint)_ooxmlId++); string atomLabelName = "Atom " + alc.ParentAtom; Int64Value width = OoXmlHelper.ScaleCsTtfToEmu(alc.Character.Width, _meanBondLength); Int64Value height = OoXmlHelper.ScaleCsTtfToEmu(alc.Character.Height, _meanBondLength); if (alc.IsSmaller) { width = OoXmlHelper.ScaleCsTtfSubScriptToEmu(alc.Character.Width, _meanBondLength); height = OoXmlHelper.ScaleCsTtfSubScriptToEmu(alc.Character.Height, _meanBondLength); } Int64Value top = OoXmlHelper.ScaleCmlToEmu(characterPosition.Y); Int64Value left = OoXmlHelper.ScaleCmlToEmu(characterPosition.X); // Set variable true to show bounding box of (every) character if (_options.ShowCharacterBoundingBoxes) { Rect boundingBox = new Rect(new Point(left, top), new Size(width, height)); DrawCharacterBox(wordprocessingGroup, boundingBox, "00ff00", 0.25); } Wps.WordprocessingShape shape = new Wps.WordprocessingShape(); Wps.NonVisualDrawingProperties nonVisualDrawingProperties = new Wps.NonVisualDrawingProperties() { Id = id, Name = atomLabelName }; Wps.NonVisualDrawingShapeProperties nonVisualDrawingShapeProperties = new Wps.NonVisualDrawingShapeProperties(); Wps.ShapeProperties shapeProperties = new Wps.ShapeProperties(); A.Transform2D transform2D = new A.Transform2D(); A.Offset offset = new A.Offset { X = left, Y = top }; A.Extents extents = new A.Extents { Cx = width, Cy = height }; transform2D.Append(offset); transform2D.Append(extents); A.CustomGeometry geometry = new A.CustomGeometry(); A.AdjustValueList adjustValueList = new A.AdjustValueList(); A.Rectangle rectangle = new A.Rectangle { Left = "l", Top = "t", Right = "r", Bottom = "b" }; A.PathList pathList = new A.PathList(); A.Path path = new A.Path { Width = width, Height = height }; foreach (TtfContour contour in alc.Character.Contours) { int i = 0; while (i < contour.Points.Count) { TtfPoint thisPoint = contour.Points[i]; TtfPoint nextPoint = null; if (i < contour.Points.Count - 1) { nextPoint = contour.Points[i + 1]; } switch (thisPoint.Type) { case TtfPoint.PointType.Start: A.MoveTo moveTo = new A.MoveTo(); if (alc.IsSmaller) { A.Point point = MakeSubscriptPoint(thisPoint); moveTo.Append(point); path.Append(moveTo); } else { A.Point point = MakeNormalPoint(thisPoint); moveTo.Append(point); path.Append(moveTo); } i++; break; case TtfPoint.PointType.Line: A.LineTo lineTo = new A.LineTo(); if (alc.IsSmaller) { A.Point point = MakeSubscriptPoint(thisPoint); lineTo.Append(point); path.Append(lineTo); } else { A.Point point = MakeNormalPoint(thisPoint); lineTo.Append(point); path.Append(lineTo); } i++; break; case TtfPoint.PointType.CurveOff: A.QuadraticBezierCurveTo quadraticBezierCurveTo = new A.QuadraticBezierCurveTo(); if (alc.IsSmaller) { A.Point pointA = MakeSubscriptPoint(thisPoint); A.Point pointB = MakeSubscriptPoint(nextPoint); quadraticBezierCurveTo.Append(pointA); quadraticBezierCurveTo.Append(pointB); path.Append(quadraticBezierCurveTo); } else { A.Point pointA = MakeNormalPoint(thisPoint); A.Point pointB = MakeNormalPoint(nextPoint); quadraticBezierCurveTo.Append(pointA); quadraticBezierCurveTo.Append(pointB); path.Append(quadraticBezierCurveTo); } i++; i++; break; case TtfPoint.PointType.CurveOn: // Should never get here ! i++; break; } } A.CloseShapePath closeShapePath = new A.CloseShapePath(); path.Append(closeShapePath); } pathList.Append(path); geometry.Append(adjustValueList); geometry.Append(rectangle); geometry.Append(pathList); A.SolidFill solidFill = new A.SolidFill(); // Set Colour A.RgbColorModelHex rgbColorModelHex = new A.RgbColorModelHex { Val = alc.Colour }; solidFill.Append(rgbColorModelHex); shapeProperties.Append(transform2D); shapeProperties.Append(geometry); shapeProperties.Append(solidFill); OoXmlHelper.AppendShapeStyle(shape, nonVisualDrawingProperties, nonVisualDrawingShapeProperties, shapeProperties); wordprocessingGroup.Append(shape); // Local Functions A.Point MakeSubscriptPoint(TtfPoint ttfPoint) { A.Point pp = new A.Point { X = $"{OoXmlHelper.ScaleCsTtfSubScriptToEmu(ttfPoint.X - alc.Character.OriginX, _meanBondLength)}", Y = $"{OoXmlHelper.ScaleCsTtfSubScriptToEmu(alc.Character.Height + ttfPoint.Y - (alc.Character.Height + alc.Character.OriginY), _meanBondLength)}" }; return(pp); } A.Point MakeNormalPoint(TtfPoint ttfPoint) { A.Point pp = new A.Point { X = $"{OoXmlHelper.ScaleCsTtfToEmu(ttfPoint.X - alc.Character.OriginX, _meanBondLength)}", Y = $"{OoXmlHelper.ScaleCsTtfToEmu(alc.Character.Height + ttfPoint.Y - (alc.Character.Height + alc.Character.OriginY), _meanBondLength)}" }; return(pp); } }
public void CreateFunctionalGroupCharacters(Atom atom, Options options) { FunctionalGroup fg = atom.Element as FunctionalGroup; double baFromNorth = Vector.AngleBetween(BasicGeometry.ScreenNorth, atom.BalancingVector(true)); CompassPoints nesw = BasicGeometry.SnapTo2EW(baFromNorth); bool reverse = nesw == CompassPoints.West; #region Set Up Atom Colours string atomColour = "000000"; if (options.ColouredAtoms) { if (!string.IsNullOrEmpty(fg.Colour)) { atomColour = fg.Colour; // Strip out # as OoXml does not use it atomColour = atomColour.Replace("#", ""); } } #endregion Set Up Atom Colours List <FunctionalGroupTerm> terms = fg.ExpandIntoTerms(reverse); #region Step 1 - Generate the characters and measure Bounding Boxes var cursorPosition = atom.Position; List <AtomLabelCharacter> fgCharacters = new List <AtomLabelCharacter>(); TtfCharacter hydrogenCharacter = _TtfCharacterSet['H']; Rect fgBoundingBox = Rect.Empty; Rect anchorBoundingBox = Rect.Empty; foreach (var term in terms) { foreach (var part in term.Parts) { foreach (char c in part.Text) { Rect bb = AddCharacter(c, part.Type); fgBoundingBox.Union(bb); if (term.IsAnchor) { anchorBoundingBox.Union(bb); } } } } #endregion Step 1 - Generate the characters and measure Bounding Boxes #region Step 2 - Move all characters such that the anchor term is centered on the atom position double offsetX; double offsetY; if (reverse) { offsetX = fgBoundingBox.Width - anchorBoundingBox.Width / 2; offsetY = anchorBoundingBox.Height / 2; } else { offsetX = anchorBoundingBox.Width / 2; offsetY = anchorBoundingBox.Height / 2; } offsetY = offsetY + anchorBoundingBox.Top - atom.Position.Y; foreach (var alc in fgCharacters) { alc.Position = new Point(alc.Position.X - offsetX, alc.Position.Y - offsetY); } #endregion Step 2 - Move all characters such that the anchor term is centered on the atom position #region Step 3 - Transfer characters into main list foreach (var alc in fgCharacters) { _AtomLabelCharacters.Add(alc); } #endregion Step 3 - Transfer characters into main list #region Step 4 - Convex Hull _convexhHulls.Add(atom.Path, ConvexHull(atom.Path)); #endregion Step 4 - Convex Hull // Local Function Rect AddCharacter(char c, FunctionalGroupPartType type) { TtfCharacter ttf = _TtfCharacterSet[c]; var thisCharacterPosition = GetCharacterPosition(cursorPosition, ttf); var alc = new AtomLabelCharacter(thisCharacterPosition, ttf, atomColour, c, atom.Path, atom.Parent.Path); alc.IsSubScript = type == FunctionalGroupPartType.Subscript; alc.IsSuperScript = type == FunctionalGroupPartType.Superscript; alc.IsSmaller = alc.IsSubScript || alc.IsSuperScript; Rect thisBoundingBox; if (alc.IsSmaller) { // Start by assuming it's SubScript thisCharacterPosition.Offset(0, OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Height * OoXmlHelper.SUBSCRIPT_DROP_FACTOR, _meanBondLength)); if (alc.IsSuperScript) { // Shift up by height of H to make it SuperScript thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Height, _meanBondLength)); } // Reset the character's position alc.Position = thisCharacterPosition; thisBoundingBox = new Rect(alc.Position, new Size(OoXmlHelper.ScaleCsTtfToCml(alc.Character.Width, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, OoXmlHelper.ScaleCsTtfToCml(alc.Character.Height, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR)); cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(alc.Character.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } else { thisBoundingBox = new Rect(alc.Position, new Size(OoXmlHelper.ScaleCsTtfToCml(alc.Character.Width, _meanBondLength), OoXmlHelper.ScaleCsTtfToCml(alc.Character.Height, _meanBondLength))); cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(alc.Character.IncrementX, _meanBondLength), 0); } fgCharacters.Add(alc); return(thisBoundingBox); } }
public void CreateElementCharacters(Atom atom, Options options) { string module = $"{_product}.{_class}.{MethodBase.GetCurrentMethod().Name}()"; //Point atomCentre = new Point((double)atom.X2, (double)atom.Y2); string atomLabel = atom.Element.Symbol; Rect labelBounds; // Get Charge and Isotope values for use later on int iCharge = atom.FormalCharge ?? 0; int iAbsCharge = Math.Abs(iCharge); int isoValue = atom.IsotopeNumber ?? 0; // Get Implicit Hydrogen Count for use later on int implicitHCount = atom.ImplicitHydrogenCount; Point cursorPosition = atom.Position; Point chargeCursorPosition = atom.Position; Point isotopeCursorPosition = atom.Position; double lastOffset = 0; int bondCount = atom.Bonds.ToList().Count; #region Decide if atom label is to be displayed bool showLabel = true; if (atomLabel == "C") { if (atom.ShowSymbol.HasValue) { showLabel = atom.ShowSymbol.Value; } else { if (atom.IsInRing || bondCount > 1) { showLabel = false; } if (bondCount == 2) { Point p1 = atom.Bonds.ToList()[0].OtherAtom(atom).Position; Point p2 = atom.Bonds.ToList()[1].OtherAtom(atom).Position; double angle1 = Vector.AngleBetween(-(atom.Position - p1), atom.Position - p2); if (Math.Abs(angle1) < 8) { showLabel = true; } } } // Force on if atom has charge if (iAbsCharge > 0) { showLabel = true; } // Force on if atom has isotope value if (isoValue > 0) { showLabel = true; } } #endregion Decide if atom label is to be displayed if (showLabel) { #region Set Up Atom Colours string atomColour = "000000"; if (options.ColouredAtoms) { if (atom.Element.Colour != null) { atomColour = atom.Element.Colour; // Strip out # as OoXml does not use it atomColour = atomColour.Replace("#", ""); } } #endregion Set Up Atom Colours #region Step 1 - Measure Bounding Box for all Characters of label double xMin = double.MaxValue; double yMin = double.MaxValue; double xMax = double.MinValue; double yMax = double.MinValue; Point thisCharacterPosition; for (int idx = 0; idx < atomLabel.Length; idx++) { char chr = atomLabel[idx]; TtfCharacter c = _TtfCharacterSet[chr]; if (c != null) { thisCharacterPosition = GetCharacterPosition(cursorPosition, c); xMin = Math.Min(xMin, thisCharacterPosition.X); yMin = Math.Min(yMin, thisCharacterPosition.Y); xMax = Math.Max(xMax, thisCharacterPosition.X + OoXmlHelper.ScaleCsTtfToCml(c.Width, _meanBondLength)); yMax = Math.Max(yMax, thisCharacterPosition.Y + OoXmlHelper.ScaleCsTtfToCml(c.Height, _meanBondLength)); if (idx < atomLabel.Length - 1) { // Move to next Character position cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(c.IncrementX, _meanBondLength), 0); } } } #endregion Step 1 - Measure Bounding Box for all Characters of label #region Step 2 - Reset Cursor such that the text is centered about the atom's co-ordinates double width = xMax - xMin; double height = yMax - yMin; cursorPosition = new Point(atom.Position.X - width / 2, atom.Position.Y + height / 2); chargeCursorPosition = new Point(cursorPosition.X, cursorPosition.Y); isotopeCursorPosition = new Point(cursorPosition.X, cursorPosition.Y); labelBounds = new Rect(cursorPosition, new Size(width, height)); #endregion Step 2 - Reset Cursor such that the text is centered about the atom's co-ordinates #region Step 3 - Place the characters foreach (char chr in atomLabel) { TtfCharacter c = _TtfCharacterSet[chr]; if (c != null) { thisCharacterPosition = GetCharacterPosition(cursorPosition, c); AtomLabelCharacter alc = new AtomLabelCharacter(thisCharacterPosition, c, atomColour, chr, atom.Path, atom.Parent.Path); _AtomLabelCharacters.Add(alc); // Move to next Character position lastOffset = OoXmlHelper.ScaleCsTtfToCml(c.IncrementX, _meanBondLength); cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(c.IncrementX, _meanBondLength), 0); chargeCursorPosition = new Point(cursorPosition.X, cursorPosition.Y); } } #endregion Step 3 - Place the characters #region Determine NESW double baFromNorth = Vector.AngleBetween(BasicGeometry.ScreenNorth, atom.BalancingVector(true)); CompassPoints nesw = CompassPoints.East; if (bondCount == 1) { nesw = BasicGeometry.SnapTo2EW(baFromNorth); } else { nesw = BasicGeometry.SnapTo4NESW(baFromNorth); } #endregion Determine NESW #region Step 4 - Add Charge if required if (iCharge != 0) { TtfCharacter hydrogenCharacter = _TtfCharacterSet['H']; char sign = '.'; TtfCharacter chargeSignCharacter = null; if (iCharge >= 1) { sign = '+'; chargeSignCharacter = _TtfCharacterSet['+']; } else if (iCharge <= 1) { sign = '-'; chargeSignCharacter = _TtfCharacterSet['-']; } if (iAbsCharge > 1) { string digits = iAbsCharge.ToString(); // Insert digits foreach (char chr in digits) { TtfCharacter chargeValueCharacter = _TtfCharacterSet[chr]; thisCharacterPosition = GetCharacterPosition(chargeCursorPosition, chargeValueCharacter); // Raise the superscript Character thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(chargeValueCharacter.Height * OoXmlHelper.CS_SUPERSCRIPT_RAISE_FACTOR, _meanBondLength)); AtomLabelCharacter alcc = new AtomLabelCharacter(thisCharacterPosition, chargeValueCharacter, atomColour, chr, atom.Path, atom.Parent.Path); alcc.IsSmaller = true; alcc.IsSubScript = true; _AtomLabelCharacters.Add(alcc); // Move to next Character position chargeCursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(chargeValueCharacter.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(chargeValueCharacter.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } } // Insert sign at raised position thisCharacterPosition = GetCharacterPosition(chargeCursorPosition, chargeSignCharacter); thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Height * OoXmlHelper.CS_SUPERSCRIPT_RAISE_FACTOR, _meanBondLength)); thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(chargeSignCharacter.Height / 2 * OoXmlHelper.CS_SUPERSCRIPT_RAISE_FACTOR, _meanBondLength)); AtomLabelCharacter alcs = new AtomLabelCharacter(thisCharacterPosition, chargeSignCharacter, atomColour, sign, atom.Path, atom.Parent.Path); alcs.IsSmaller = true; alcs.IsSubScript = true; _AtomLabelCharacters.Add(alcs); if (iAbsCharge != 0) { cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(chargeSignCharacter.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } } #endregion Step 4 - Add Charge if required #region Step 5 - Add Implicit H if required if (options.ShowHydrogens && implicitHCount > 0) { TtfCharacter hydrogenCharacter = _TtfCharacterSet['H']; string numbers = "012345"; TtfCharacter implicitValueCharacter = _TtfCharacterSet[numbers[implicitHCount]]; #region Add H if (hydrogenCharacter != null) { switch (nesw) { case CompassPoints.North: if (atom.Bonds.ToList().Count > 1) { cursorPosition.X = labelBounds.X + (labelBounds.Width / 2) - (OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Width, _meanBondLength) / 2); cursorPosition.Y = cursorPosition.Y + OoXmlHelper.ScaleCsTtfToCml(-hydrogenCharacter.Height, _meanBondLength) - OoXmlHelper.CHARACTER_VERTICAL_SPACING; if (iCharge > 0) { if (implicitHCount > 1) { cursorPosition.Offset(0, OoXmlHelper.ScaleCsTtfToCml( -implicitValueCharacter.Height * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR / 2, _meanBondLength) - OoXmlHelper.CHARACTER_VERTICAL_SPACING); } } } break; case CompassPoints.East: // Leave as is break; case CompassPoints.South: if (atom.Bonds.ToList().Count > 1) { cursorPosition.X = labelBounds.X + (labelBounds.Width / 2) - (OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Width, _meanBondLength) / 2); cursorPosition.Y = cursorPosition.Y + OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Height, _meanBondLength) + OoXmlHelper.CHARACTER_VERTICAL_SPACING; } break; case CompassPoints.West: if (implicitHCount == 1) { if (iAbsCharge == 0) { cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(-(hydrogenCharacter.IncrementX * 2), _meanBondLength), 0); } else { cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(-((hydrogenCharacter.IncrementX * 2 + implicitValueCharacter.IncrementX * 1.25)), _meanBondLength), 0); } } else { if (iAbsCharge == 0) { cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(-(hydrogenCharacter.IncrementX * 2.5), _meanBondLength), 0); } else { cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(-((hydrogenCharacter.IncrementX * 2 + implicitValueCharacter.IncrementX * 1.25)), _meanBondLength), 0); } } break; } thisCharacterPosition = GetCharacterPosition(cursorPosition, hydrogenCharacter); AtomLabelCharacter alc = new AtomLabelCharacter(thisCharacterPosition, hydrogenCharacter, atomColour, 'H', atom.Path, atom.Parent.Path); _AtomLabelCharacters.Add(alc); // Move to next Character position cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.IncrementX, _meanBondLength), 0); if (nesw == CompassPoints.East) { chargeCursorPosition = new Point(cursorPosition.X, cursorPosition.Y); } if (nesw == CompassPoints.West) { isotopeCursorPosition = new Point(thisCharacterPosition.X, isotopeCursorPosition.Y); } } #endregion Add H #region Add number if (implicitHCount > 1) { if (implicitValueCharacter != null) { thisCharacterPosition = GetCharacterPosition(cursorPosition, implicitValueCharacter); // Drop the subscript Character thisCharacterPosition.Offset(0, OoXmlHelper.ScaleCsTtfToCml(hydrogenCharacter.Width * OoXmlHelper.SUBSCRIPT_DROP_FACTOR, _meanBondLength)); AtomLabelCharacter alc = new AtomLabelCharacter(thisCharacterPosition, implicitValueCharacter, atomColour, numbers[implicitHCount], atom.Path, atom.Parent.Path); alc.IsSmaller = true; alc.IsSubScript = true; _AtomLabelCharacters.Add(alc); // Move to next Character position cursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(implicitValueCharacter.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } } #endregion Add number } #endregion Step 5 - Add Implicit H if required #region Step 6 - Add IsoTope Number if required if (isoValue > 0) { string digits = isoValue.ToString(); xMin = double.MaxValue; yMin = double.MaxValue; xMax = double.MinValue; yMax = double.MinValue; Point isoOrigin = isotopeCursorPosition; // Calculate width of digits foreach (char chr in digits) { TtfCharacter c = _TtfCharacterSet[chr]; thisCharacterPosition = GetCharacterPosition(isotopeCursorPosition, c); // Raise the superscript Character thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(c.Height * OoXmlHelper.CS_SUPERSCRIPT_RAISE_FACTOR, _meanBondLength)); xMin = Math.Min(xMin, thisCharacterPosition.X); yMin = Math.Min(yMin, thisCharacterPosition.Y); xMax = Math.Max(xMax, thisCharacterPosition.X + OoXmlHelper.ScaleCsTtfToCml(c.Width, _meanBondLength)); yMax = Math.Max(yMax, thisCharacterPosition.Y + OoXmlHelper.ScaleCsTtfToCml(c.Height, _meanBondLength)); // Move to next Character position isotopeCursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(c.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } // Re-position Isotope Cursor width = xMax - xMin; isotopeCursorPosition = new Point(isoOrigin.X - width, isoOrigin.Y); // Insert digits foreach (char chr in digits) { TtfCharacter c = _TtfCharacterSet[chr]; thisCharacterPosition = GetCharacterPosition(isotopeCursorPosition, c); // Raise the superscript Character thisCharacterPosition.Offset(0, -OoXmlHelper.ScaleCsTtfToCml(c.Height * OoXmlHelper.CS_SUPERSCRIPT_RAISE_FACTOR, _meanBondLength)); AtomLabelCharacter alcc = new AtomLabelCharacter(thisCharacterPosition, c, atomColour, chr, atom.Path, atom.Parent.Path); alcc.IsSmaller = true; alcc.IsSubScript = true; _AtomLabelCharacters.Add(alcc); // Move to next Character position isotopeCursorPosition.Offset(OoXmlHelper.ScaleCsTtfToCml(c.IncrementX, _meanBondLength) * OoXmlHelper.SUBSCRIPT_SCALE_FACTOR, 0); } } #endregion Step 6 - Add IsoTope Number if required #region Step 7 - Create Convex Hull _convexhHulls.Add(atom.Path, ConvexHull(atom.Path)); #endregion Step 7 - Create Convex Hull } }