Example #1
0
        //draws the isotope label at ten-o-clock
        private LabelMetrics DrawIsotopeLabel(DrawingContext drawingContext, AtomTextMetrics mainAtomMetrics, AtomTextMetrics hMetrics)
        {
            Debug.Assert(Isotope != null);

            string isoLabel    = Isotope.ToString();
            var    isotopeText = new IsotopeLabelText(isoLabel, PixelsPerDip());

            Vector isotopeOffsetVector = BasicGeometry.ScreenNorth * GlyphText.SymbolSize;
            Matrix rotator             = new Matrix();
            double angle = -60;

            //avoid overlap of label and hydrogens
            if (hMetrics != null && ParentAtom.GetDefaultHOrientation() == CompassPoints.West)
            {
                angle = -35;
            }

            rotator.Rotate(angle);
            isotopeOffsetVector = isotopeOffsetVector * rotator;
            Point isoCenter = mainAtomMetrics.Geocenter + isotopeOffsetVector;

            isotopeText.MeasureAtCenter(isoCenter);
            isotopeText.Fill = Fill;
            isotopeText.DrawAtBottomLeft(isotopeText.TextMetrics.BoundingBox.BottomLeft, drawingContext);
            return(isotopeText.TextMetrics);
        }
Example #2
0
 /// <summary>
 /// Draws the subscripted group text
 /// </summary>
 /// <param name="drawingContext">DC supplied by OnRender</param>
 /// <param name="measure">Provided by calling the Measure method previously</param>
 /// <param name="pixelsPerDip"></param>
 /// <param name="fill"></param>
 public void DrawSelf(DrawingContext drawingContext, AtomTextMetrics measure, float pixelsPerDip, Brush fill)
 {
     _mainText.Fill = fill;
     _mainText.DrawAtBottomLeft(measure.BoundingBox.BottomLeft, drawingContext);
     if (_subText != null)
     {
         _subText.Fill = fill;
         _subText.DrawAtBottomLeft(_subText.TextMetrics.BoundingBox.BottomLeft, drawingContext);
     }
 }
Example #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="drawingContext"></param>
        /// <param name="mainAtomMetrics"></param>
        /// <param name="hMetrics"></param>
        /// <param name="isoMetrics"></param>
        /// <param name="defaultHOrientation"></param>
        /// <returns></returns>
        private LabelMetrics DrawCharges(DrawingContext drawingContext,
                                         AtomTextMetrics mainAtomMetrics,
                                         AtomTextMetrics hMetrics,
                                         LabelMetrics isoMetrics,
                                         CompassPoints defaultHOrientation)
        {
            var chargeString = AtomHelpers.GetChargeString(Charge);
            var chargeText   = DrawChargeOrRadical(drawingContext, mainAtomMetrics, hMetrics, isoMetrics, chargeString, Fill, defaultHOrientation);

            chargeText.TextMetrics.FlattenedPath = chargeText.TextRun.GetOutline();
            return(chargeText.TextMetrics);
        }
Example #4
0
 public void MeasureAtBottomLeft(Point bottomLeft, float PixelsPerDip)
 {
     GlyphInfo   = GlyphUtils.GetGlyphsAndInfo(Text, PixelsPerDip, out GlyphRun groupGlyphRun, bottomLeft, _glyphTypeface, TypeSize);
     TextRun     = groupGlyphRun;
     TextMetrics = new AtomTextMetrics
     {
         BoundingBox      = groupGlyphRun.GetBoundingBox(bottomLeft),
         Geocenter        = bottomLeft,
         TotalBoundingBox = groupGlyphRun.GetBoundingBox(bottomLeft),
         FlattenedPath    = GlyphUtils.GetOutline(TextRun),
         OffsetVector     = new Vector(0.0d, 0.0d)
     };
 }
Example #5
0
        /// <param name="drawingContext"></param>
        /// <param name="mainAtomMetrics">
        /// </param>
        /// <param name="hMetrics">
        /// </param>
        /// <param name="isoMetrics">
        /// </param>
        /// <param name="chargeString"></param>
        /// <param name="fill"></param>
        /// <param name="defaultHOrientation"></param>
        /// <returns></returns>
        /// <summary>
        /// Draws a charge or radical label at the given point
        /// </summary>
        /// <returns></returns>
        private ChargeLabelText DrawChargeOrRadical(DrawingContext drawingContext, AtomTextMetrics mainAtomMetrics, AtomTextMetrics hMetrics, LabelMetrics isoMetrics, string chargeString, Brush fill, CompassPoints defaultHOrientation)
        {
            ChargeLabelText chargeText = new ChargeLabelText(chargeString, PixelsPerDip());

            //try to place the charge at 2 o clock to the atom
            Vector chargeOffset = BasicGeometry.ScreenNorth * GlyphText.SymbolSize * 0.9;

            RotateUntilClear(mainAtomMetrics, hMetrics, isoMetrics, chargeOffset, chargeText, out var chargeCenter, defaultHOrientation);
            chargeText.MeasureAtCenter(chargeCenter);
            chargeText.Fill = fill;
            chargeText.DrawAtBottomLeft(chargeText.TextMetrics.BoundingBox.BottomLeft, drawingContext);
            return(chargeText);
        }
Example #6
0
            /// <summary>
            /// Measures the dimensions of the atom prior to rendering
            /// </summary>
            /// <param name="parentMetrics">Metrics of the parent atom</param>
            /// <param name="direction">Orientation of the group relative to the parent atom, i.e. NESW</param>
            /// <returns>AtomTextMetrics object describing placement</returns>
            public AtomTextMetrics Measure(AtomTextMetrics parentMetrics, CompassPoints direction, float pixelsPerDip)
            {
                _subText = null;

                List <Point> mainOutline;

                //first, get some initial size measurements
                _mainText = new GlyphText(Text, SymbolTypeface, _fontSize, pixelsPerDip);
                _mainText.Premeasure();

                //measure up the subscript (if we have one)
                string subscriptText = AtomHelpers.GetSubText(Count);

                if (subscriptText != "")
                {
                    _subText = new SubLabelText(subscriptText, pixelsPerDip);
                    _subText.Premeasure();
                }

                //calculate the center of the H Atom depending on the direction
                var groupCenter = GetAdjunctCenter(parentMetrics, direction, _mainText.GlyphInfo, _subText?.GlyphInfo);

                //remeasure the main text
                _mainText.MeasureAtCenter(groupCenter);

                mainOutline = _mainText.FlattenedPath;

                if (_subText != null)
                //get the offset for the subscript
                {
                    Vector subscriptOffset = new Vector(_mainText.TextMetrics.TotalBoundingBox.Width + _mainText.TrailingBearing + _subText.LeadingBearing,
                                                        _subText.TextMetrics.BoundingBox.Height / 2);
                    Point subBottomLeft = _mainText.TextMetrics.TotalBoundingBox.BottomLeft + subscriptOffset;
                    _subText.MeasureAtBottomLeft(subBottomLeft, pixelsPerDip);
                    //merge the total bounding boxes
                    _mainText.Union(_subText);
                    mainOutline.AddRange(_subText.FlattenedPath);
                }
                //return the placement metrics for the subscripted atom.
                AtomTextMetrics result = new AtomTextMetrics
                {
                    Geocenter        = groupCenter,
                    BoundingBox      = _mainText.TextMetrics.BoundingBox,
                    TotalBoundingBox = _mainText.TextMetrics.TotalBoundingBox,
                    FlattenedPath    = mainOutline
                };

                return(result);
            }
Example #7
0
        private static void RotateUntilClear(AtomTextMetrics mainAtomMetrics, AtomTextMetrics hMetrics, LabelMetrics isoMetrics,
                                             Vector labelOffset, GlyphText labelText, out Point labelCenter, CompassPoints defHOrientation)
        {
            Matrix rotator = new Matrix();
            double angle   = Globals.ClockDirections.II.ToDegrees();

            rotator.Rotate(angle);

            labelOffset = labelOffset * rotator;
            Rect bb  = new Rect();
            Rect bb2 = new Rect();

            if (hMetrics != null)
            {
                bb = hMetrics.TotalBoundingBox;
            }
            if (isoMetrics != null)
            {
                bb2 = isoMetrics.BoundingBox;
            }
            labelCenter = mainAtomMetrics.Geocenter + labelOffset;
            labelText.MeasureAtCenter(labelCenter);

            double increment;

            if (defHOrientation == CompassPoints.East)
            {
                increment = -10;
            }
            else
            {
                increment = 10;
            }
            while (labelText.CollidesWith(mainAtomMetrics.TotalBoundingBox, bb,
                                          bb2) & Math.Abs(angle - 30) > 0.001)
            {
                rotator = new Matrix();

                angle += increment;
                rotator.Rotate(increment);
                labelOffset = labelOffset * rotator;
                labelCenter = mainAtomMetrics.Geocenter + labelOffset;
                labelText.MeasureAtCenter(labelCenter);
            }
        }
Example #8
0
        public void MeasureAtCenter(Point center)
        {
            GlyphInfo = GlyphUtils.GetGlyphsAndInfo(Text, PixelsPerDip, out GlyphRun groupGlyphRun, center, _glyphTypeface, TypeSize);
            //compensate the main offset vector for any descenders

            Vector mainOffset = GlyphUtils.GetOffsetVector(groupGlyphRun, TypeSize) +
                                new Vector(0.0, -MaxBaselineOffset);
            var    bb = groupGlyphRun.GetBoundingBox(center + mainOffset);
            Vector textFormatterOffset = new Vector(mainOffset.X, -FirstBearing(groupGlyphRun) - bb.Height / 2);

            TextRun     = groupGlyphRun;
            TextMetrics = new AtomTextMetrics
            {
                BoundingBox         = bb,
                Geocenter           = center,
                TotalBoundingBox    = groupGlyphRun.GetBoundingBox(center + mainOffset),
                OffsetVector        = mainOffset,
                TextFormatterOffset = textFormatterOffset
            };
        }
Example #9
0
            /// <summary>
            /// Gets the center point of an atom adjunct (like an implicit hydrogen plus subscripts)
            /// The Adjunct in NH2 is H2
            /// </summary>
            /// <param name="parentMetrics">Metrics of the parent atom</param>
            /// <param name="direction">NESW direction of the adjunct respective to the atom</param>
            /// <param name="adjunctGlyphInfo">Initial measurements of the adjunct</param>
            /// <param name="subscriptInfo">Initial measurements of the subscript (can be null for no subscripts)</param>
            /// <returns></returns>
            private static Point GetAdjunctCenter(AtomTextMetrics parentMetrics, CompassPoints direction,
                                                  GlyphInfo adjunctGlyphInfo, GlyphInfo?subscriptInfo = null)
            {
                Point  adjunctCenter;
                double charHeight   = (GlyphUtils.GlyphTypeface.Baseline * _fontSize);
                double adjunctWidth = (parentMetrics.BoundingBox.Width + adjunctGlyphInfo.Width) / 2;

                switch (direction)
                {
                //all addition in this routine is *vector* addition.
                //We are not adding absolute X and Y values
                case CompassPoints.East:
                default:
                    adjunctCenter = parentMetrics.Geocenter + BasicGeometry.ScreenEast * adjunctWidth;
                    break;

                case CompassPoints.North:
                    adjunctCenter = parentMetrics.Geocenter +
                                    BasicGeometry.ScreenNorth * charHeight;
                    break;

                case CompassPoints.West:
                    if (subscriptInfo != null)
                    {
                        adjunctCenter = parentMetrics.Geocenter + (BasicGeometry.ScreenWest *
                                                                   (adjunctWidth + subscriptInfo.Value.Width));
                    }
                    else
                    {
                        adjunctCenter = parentMetrics.Geocenter + (BasicGeometry.ScreenWest * (adjunctWidth));
                    }
                    break;

                case CompassPoints.South:
                    adjunctCenter = parentMetrics.Geocenter +
                                    BasicGeometry.ScreenSouth * charHeight;
                    break;
                }
                return(adjunctCenter);
            }
Example #10
0
        private void RenderAtom(DrawingContext drawingContext)
        {
            //renders the atom complete with charges, hydrogens and labels.
            //this code is *complex* - alter it at your own risk!

            List <Point> symbolPoints   = new List <Point>();
            List <Point> hydrogenPoints = new List <Point>();

            //private variables used to keep track of onscreen visuals
            AtomTextMetrics  hydrogenMetrics  = null;
            LabelMetrics     isoMetrics       = null;
            SubscriptedGroup subscriptedGroup = null;

            Hull = new List <Point>();

            //stage 1:  measure up the main atom symbol in position
            //we need the metrics first
            if (AtomSymbol != "")
            {
                var symbolText = new GlyphText(AtomSymbol,
                                               SymbolTypeface, GlyphText.SymbolSize, PixelsPerDip());
                symbolText.MeasureAtCenter(Position);
                //grab the hull for later
                if (symbolText.FlattenedPath != null)
                {
                    Hull.AddRange(symbolText.FlattenedPath);
                }
            }

            //stage 2.  grab the main atom metrics br drawing it

            var mainAtomMetrics = DrawSelf(drawingContext);

            //if it's a vertex atom we need the hull
            if (AtomSymbol == "")
            {
                Hull.AddRange(mainAtomMetrics.FlattenedPath);
            }

            //stage 3:  measure up the hydrogens
            //if we have implicit hydrogens and we have an explicit label, draw them
            if (ImplicitHydrogenCount > 0 && AtomSymbol != "")
            {
                var defaultHOrientation = ParentAtom.GetDefaultHOrientation();

                subscriptedGroup = new SubscriptedGroup(ImplicitHydrogenCount, "H", GlyphText.SymbolSize);
                hydrogenMetrics  = subscriptedGroup.Measure(mainAtomMetrics, defaultHOrientation, PixelsPerDip());

                subscriptedGroup.DrawSelf(drawingContext, hydrogenMetrics, PixelsPerDip(), Fill);
                hydrogenPoints = hydrogenMetrics.FlattenedPath;
                Hull.AddRange(hydrogenPoints);
            }

            //stage 6:  draw an isotope label if needed
            if (Isotope != null)
            {
                isoMetrics = DrawIsotopeLabel(drawingContext, mainAtomMetrics, hydrogenMetrics);
                Hull.AddRange(isoMetrics.Corners);
            }

            //stage7:  draw any charges
            if ((Charge ?? 0) != 0)
            {
                LabelMetrics cMetrics = DrawCharges(drawingContext, mainAtomMetrics, hydrogenMetrics, isoMetrics, ParentAtom.GetDefaultHOrientation());
                Hull.AddRange(cMetrics.FlattenedPath);
            }

            //stage 8:  recalculate the hull
            if (Hull.Any())
            {
                //sort the points properly before doing a hull calculation
                var sortedHull = (from Point p in Hull
                                  orderby p.X, p.Y descending
                                  select p).ToList();

                Hull = Geometry <Point> .GetHull(sortedHull, p => p);

                // Diag: Show the Hull
#if DEBUG
#if SHOWHULLS
                ShowHull(Hull, drawingContext);
#endif
#endif
                // End Diag
            }
            // Diag: Show the Atom Point
#if DEBUG
#if SHOWATOMCENTRES
            drawingContext.DrawEllipse(Brushes.Red, null, ParentAtom.Position, 5, 5);
#endif
#endif
            // End Diag
        }