コード例 #1
0
 /// <inheritdoc/>
 public override IRenderingElement GenerateRingElements(IBond bond, IRing ring, RendererModel model)
 {
     if (RingIsAromatic(ring) &&
         model.GetShowAromaticity() &&
         ring.Atoms.Count < model.GetMaxDrawableAromaticRing())
     {
         var pair = new ElementGroup();
         if (model.GetCDKStyleAromaticity())
         {
             pair.Add(GenerateBondElement(bond, BondOrder.Single, model));
             base.SetOverrideColor(WPF.Media.Colors.LightGray);
             pair.Add(GenerateInnerElement(bond, ring, model));
             base.SetOverrideColor(null);
         }
         else
         {
             pair.Add(GenerateBondElement(bond, BondOrder.Single, model));
             if (!painted_rings.Contains(ring))
             {
                 painted_rings.Add(ring);
                 pair.Add(GenerateRingRingElement(bond, ring, model));
             }
         }
         return(pair);
     }
     else
     {
         return(base.GenerateRingElements(bond, ring, model));
     }
 }
コード例 #2
0
ファイル: ReactionBoxGenerator.cs プロジェクト: nksgw11/NCDK
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            if (!model.GetShowReactionBoxes())
            {
                return(null);
            }
            var separation  = model.GetBondLength() / model.GetScale();
            var totalBounds = BoundsCalculator.CalculateBounds(reaction);

            if (totalBounds.IsEmpty)
            {
                return(null);
            }

            var diagram         = new ElementGroup();
            var foregroundColor = model.GetForegroundColor();

            diagram.Add(new RectangleElement(new Rect(totalBounds.Left - separation, totalBounds.Top - separation,
                                                      totalBounds.Right + separation, totalBounds.Bottom + separation),
                                             foregroundColor));
            if (reaction.Id != null)
            {
                diagram.Add(new TextElement(new Point((totalBounds.Left + totalBounds.Right) / 2, totalBounds.Top - separation),
                                            reaction.Id, foregroundColor));
            }
            return(diagram);
        }
コード例 #3
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            if (!model.GetShowReactionBoxes())
            {
                return(null);
            }
            if (reaction.Reactants.Count == 0)
            {
                return(new ElementGroup());
            }

            double separation  = model.GetBondLength() / model.GetScale() / 2;
            var    totalBounds = BoundsCalculator.CalculateBounds(reaction.Reactants);

            ElementGroup diagram         = new ElementGroup();
            double       minX            = totalBounds.Left;
            double       minY            = totalBounds.Top;
            double       maxX            = totalBounds.Right;
            double       maxY            = totalBounds.Bottom;
            var          foregroundColor = model.GetForegroundColor();

            diagram.Add(new RectangleElement(new Rect(minX - separation, minY - separation, maxX + separation, maxY + separation), foregroundColor));
            diagram.Add(new TextElement(new Point((minX + maxX) / 2, minY - separation), "Reactants", foregroundColor));
            return(diagram);
        }
コード例 #4
0
        /// <summary>
        /// Generate the Sgroup elements for the provided atom contains.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <returns>Sgroup rendering elements</returns>
        IRenderingElement GenerateSgroups(IAtomContainer container, AtomSymbol[] symbols)
        {
            var result  = new ElementGroup();
            var sgroups = container.GetCtabSgroups();

            if (sgroups == null || !sgroups.Any())
            {
                return(result);
            }

            var symbolMap = new Dictionary <IAtom, AtomSymbol>();

            for (int i = 0; i < symbols.Length; i++)
            {
                if (symbols[i] != null)
                {
                    symbolMap[container.Atoms[i]] = symbols[i];
                }
            }

            foreach (var sgroup in sgroups)
            {
                switch (sgroup.Type)
                {
                case SgroupType.CtabAbbreviation:
                    result.Add(GenerateAbbreviationSgroup(container, sgroup));
                    break;

                case SgroupType.CtabMultipleGroup:
                    result.Add(GenerateMultipleSgroup(sgroup));
                    break;

                case SgroupType.CtabAnyPolymer:
                case SgroupType.CtabMonomer:
                case SgroupType.CtabCrossLink:
                case SgroupType.CtabCopolymer:
                case SgroupType.CtabStructureRepeatUnit:
                case SgroupType.CtabMer:
                case SgroupType.CtabGraft:
                case SgroupType.CtabModified:
                    result.Add(GeneratePolymerSgroup(sgroup, symbolMap));
                    break;

                case SgroupType.CtabComponent:
                case SgroupType.CtabMixture:
                case SgroupType.CtabFormulation:
                    result.Add(GenerateMixtureSgroup(sgroup));
                    break;

                case SgroupType.CtabGeneric:
                    // not strictly a polymer but okay to draw as one
                    result.Add(GeneratePolymerSgroup(sgroup, null));
                    break;
                }
            }

            return(result);
        }
コード例 #5
0
ファイル: BasicBondGenerator.cs プロジェクト: qize/NCDK
        private void CreateLines(Vector2 point1, Vector2 point2, double width, double dist, Color color, ElementGroup group)
        {
            var         output = GenerateDistanceData(point1, point2, dist);
            LineElement l1     = new LineElement(ToPoint(output[0]), ToPoint(output[2]), width, color);
            LineElement l2     = new LineElement(ToPoint(output[1]), ToPoint(output[3]), width, color);

            group.Add(l1);
            group.Add(l2);
        }
コード例 #6
0
        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));
            }
        }
コード例 #7
0
ファイル: LonePairGenerator.cs プロジェクト: roddickchen/NCDK
        /// <inheritdoc/>
        public IRenderingElement Generate(IAtomContainer container, RendererModel model)
        {
            ElementGroup group = new ElementGroup();

            // TODO : put into RendererModel
            const double SCREEN_RADIUS = 1.0;
            // separation between centers
            const double SCREEN_SEPARATION = 2.5;
            Color        RADICAL_COLOR     = WPF.Media.Colors.Black;

            // XXX : is this the best option?
            double ATOM_RADIUS = model.GetAtomRadius();

            double scale            = model.GetScale();
            double modelAtomRadius  = ATOM_RADIUS / scale;
            double modelPointRadius = SCREEN_RADIUS / scale;
            double modelSeparation  = SCREEN_SEPARATION / scale;

            foreach (var lonePair in container.LonePairs)
            {
                IAtom   atom   = lonePair.Atom;
                Vector2 point  = atom.Point2D.Value;
                int     align  = GeometryUtil.GetBestAlignmentForLabelXY(container, atom);
                var     center = ToPoint(point);
                var     diff   = new WPF::Vector();
                if (align == 1)
                {
                    center.X += modelAtomRadius;
                    diff.Y   += modelSeparation;
                }
                else if (align == -1)
                {
                    center.X -= modelAtomRadius;
                    diff.Y   += modelSeparation;
                }
                else if (align == 2)
                {
                    center.Y -= modelAtomRadius;
                    diff.X   += modelSeparation;
                }
                else if (align == -2)
                {
                    center.Y += modelAtomRadius;
                    diff.X   += modelSeparation;
                }
                group.Add(new OvalElement(center + diff, modelPointRadius, true, RADICAL_COLOR));
                group.Add(new OvalElement(center - diff, modelPointRadius, true, RADICAL_COLOR));
            }
            return(group);
        }
コード例 #8
0
        /// <inheritdoc/>
        public override IRenderingElement GenerateDiagram(IReaction reaction)
        {
            ElementGroup diagram = new ElementGroup();

            foreach (var generator in this.generators)
            {
                diagram.Add(generator.Generate(reaction, rendererModel));
            }

            diagram.Add(moleculeSetRenderer.GenerateDiagram(reaction.Reactants));
            diagram.Add(moleculeSetRenderer.GenerateDiagram(reaction.Products));

            return(diagram);
        }
コード例 #9
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IAtomContainer container, RendererModel model)
        {
            ElementGroup numbers = new ElementGroup();

            if (!model.GetWillDrawAtomNumbers())
            {
                return(numbers);
            }

            var     _offset = model.GetAtomNumberOffset();
            Vector2 offset  = new Vector2(_offset.X, -_offset.Y);

            offset *= (1 / model.GetScale());

            int number = 1;

            foreach (var atom in container.Atoms)
            {
                Vector2 point = atom.Point2D.Value + offset;
                numbers.Add(
                    new TextElement(ToPoint(point), number.ToString(),
                                    model.GetAtomNumberColorByType() ?
                                    model.GetAtomNumberColorer().GetAtomColor(atom) :
                                    model.GetAtomNumberTextColor()));
                number++;
            }
            return(numbers);
        }
コード例 #10
0
        /// <summary>
        /// Generate an outer glow for the provided rendering element. The glow is defined by the glow
        /// width and the stroke size.
        /// </summary>
        /// <param name="element">rendering element</param>
        /// <param name="color">color of the glow</param>
        /// <param name="glowWidth">the width of the glow</param>
        /// <param name="stroke">the stroke width</param>
        /// <returns>generated outer glow</returns>
        internal static IRenderingElement OuterGlow(IRenderingElement element, Color color, double glowWidth, double stroke)
        {
            switch (element)
            {
            case ElementGroup orgGroup:
                var newGroup = new ElementGroup();
                foreach (var child in orgGroup)
                {
                    newGroup.Add(OuterGlow(child, color, glowWidth, stroke));
                }
                return(newGroup);

            case LineElement lineElement:
                return(new LineElement(lineElement.FirstPoint, lineElement.SecondPoint, stroke + (2 * (glowWidth * stroke)), color));

            case GeneralPath org:
                if (org.Fill)
                {
                    return(org.Outline(2 * (glowWidth * stroke)).Recolor(color));
                }
                else
                {
                    return(org.Outline(stroke + (2 * (glowWidth * stroke))).Recolor(color));
                }

            default:
                throw new ArgumentException($"Cannot generate glow for rendering element,{element.GetType()}");
            }
        }
コード例 #11
0
        private static T CreateChildElement <T>(ModelElement parent, bool raiseInstantiateEvents) where T : ModelElement
        {
            var childClass = parent.Partition.DomainDataDirectory.DomainClasses
                             .FirstOrDefault(dci => typeof(T).IsAssignableFrom(dci.ImplementationClass) && !dci.ImplementationClass.IsAbstract);
            var elementOperations = new ElementOperations(parent.Store, parent.Partition);

            if (elementOperations != null)
            {
                var elementGroupPrototype = new ElementGroupPrototype(parent.Partition, childClass.Id);

                var partition    = elementOperations.ChooseMergeTarget(parent, elementGroupPrototype).Partition;
                var element      = (T)partition.ElementFactory.CreateElement(childClass);
                var elementGroup = new ElementGroup(partition);
                elementGroup.Add(element);
                elementGroup.MarkAsRoot(element);
                elementOperations.MergeElementGroup(parent, elementGroup);

                // Flag the element in the state so that the ProductStore class sees it and doesn't
                // raise the instantiation event.
                if (!raiseInstantiateEvents)
                {
                    element.Store.PropertyBag.Add(element, null);
                }

                return(element);
            }

            return(default(T));
        }
コード例 #12
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            if (!model.GetShowReactionBoxes())
            {
                return(null);
            }
            if (reaction.Products.Count == 0)
            {
                return(new ElementGroup());
            }
            double distance    = model.GetBondLength() / model.GetScale() / 2;
            Rect?  totalBounds = null;

            foreach (var molecule in reaction.Products)
            {
                var bounds = BoundsCalculator.CalculateBounds(molecule);
                if (totalBounds == null)
                {
                    totalBounds = bounds;
                }
                else
                {
                    totalBounds = Rect.Union(totalBounds.Value, bounds);
                }
            }
            if (totalBounds == null)
            {
                return(null);
            }

            ElementGroup diagram         = new ElementGroup();
            var          foregroundColor = model.GetForegroundColor();

            diagram.Add(new RectangleElement(
                            new Rect(
                                totalBounds.Value.Left - distance,
                                totalBounds.Value.Top - distance,
                                totalBounds.Value.Right + distance,
                                totalBounds.Value.Bottom + distance),
                            foregroundColor));
            diagram.Add(new TextElement(
                            new Point(
                                (totalBounds.Value.Left + totalBounds.Value.Right) / 2,
                                totalBounds.Value.Top - distance),
                            "Products", foregroundColor));
            return(diagram);
        }
コード例 #13
0
        /// <inheritdoc/>
        public override IRenderingElement GenerateDiagram(IChemObjectSet <IAtomContainer> molecules)
        {
            ElementGroup diagram = new ElementGroup();

            foreach (var molecule in molecules)
            {
                diagram.Add(atomContainerRenderer.GenerateDiagram(molecule));
            }
            return(diagram);
        }
コード例 #14
0
ファイル: BoundsGenerator.cs プロジェクト: roddickchen/NCDK
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            ElementGroup elementGroup = new ElementGroup();
            var          reactants    = reaction.Reactants;

            if (reactants != null)
            {
                elementGroup.Add(this.Generate(reactants, model));
            }

            var products = reaction.Products;

            if (products != null)
            {
                elementGroup.Add(this.Generate(products, model));
            }

            return(elementGroup);
        }
コード例 #15
0
ファイル: AbstractRenderer.cs プロジェクト: nksgw11/NCDK
        /// <summary>
        /// The main method of the renderer, that uses each of the generators
        /// to create a different set of <see cref="IRenderingElement"/>s grouped
        /// together into a tree.
        /// </summary>
        /// <param name="obj">the object of type T to draw</param>
        /// <returns>the diagram as a tree of <see cref="IRenderingElement"/>s</returns>
        public virtual IRenderingElement GenerateDiagram(T obj)
        {
            var diagram = new ElementGroup();

            foreach (var generator in this.generators)
            {
                diagram.Add(generator.Generate(obj, this.rendererModel));
            }
            return(diagram);
        }
コード例 #16
0
        /// <inheritdoc/>
        public virtual IRenderingElement Generate(IAtomContainer container, RendererModel model)
        {
            ElementGroup elementGroup = new ElementGroup();

            foreach (var atom in container.Atoms)
            {
                elementGroup.Add(MarkedElement.MarkupAtom(this.Generate(container, atom, model), atom));
            }
            return(elementGroup);
        }
コード例 #17
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            ElementGroup diagram = new ElementGroup();

            var color     = model.GetForegroundColor();
            var reactants = reaction.Reactants;

            // only draw + signs when there are more than one reactant
            if (reactants.Count > 1)
            {
                var    totalBoundsReactants = BoundsCalculator.CalculateBounds(reactants);
                var    bounds1 = BoundsCalculator.CalculateBounds(reactants[0]);
                double axis    = totalBoundsReactants.CenterY();
                foreach (var reactant in reaction.Reactants.Skip(1))
                {
                    var bounds2 = BoundsCalculator.CalculateBounds(reactant);
                    diagram.Add(MakePlus(bounds1, bounds2, axis, color));
                    bounds1 = bounds2;
                }
            }

            // only draw + signs when there are more than one products
            var products = reaction.Products;

            if (products.Count > 1)
            {
                var    totalBoundsProducts = BoundsCalculator.CalculateBounds(products);
                double axis    = totalBoundsProducts.CenterY();
                var    bounds1 = BoundsCalculator.CalculateBounds(reactants[0]);
                foreach (var product in reaction.Products.Skip(1))
                {
                    var bounds2 = BoundsCalculator.CalculateBounds(product);

                    diagram.Add(MakePlus(bounds1, bounds2, axis, color));
                    bounds1 = bounds2;
                }
            }
            return(diagram);
        }
コード例 #18
0
        /// <summary>
        /// Make an embedded text label for display in a CDK renderer. If a piece of text contains newlines
        /// they are centred aligned below each other with a line height of 1.4.
        /// </summary>
        /// <param name="font">the font to embedded</param>
        /// <param name="text">the text label</param>
        /// <param name="color">the color</param>
        /// <param name="scale">the resize, should include the model scale</param>
        /// <returns>pre-rendered element</returns>
        public static IRenderingElement EmbedText(Typeface font, double emSize, string text, Color color, double scale)
        {
            var lines = text.Split('\n');
            var group = new ElementGroup();

            double yOffset    = 0;
            double lineHeight = 1.4d;

            foreach (var line in lines)
            {
                var outline = new TextOutline(line, font, emSize).Resize(scale, -scale);
                var center  = outline.GetCenter();
                outline = outline.Translate(-center.X, -(center.Y + yOffset));

                yOffset += lineHeight * outline.GetBounds().Height;

                group.Add(GeneralPath.ShapeOf(outline.GetOutline(), color));
                var logicalBounds = outline.LogicalBounds;
                group.Add(new Bounds(logicalBounds.Left, logicalBounds.Top, logicalBounds.Right, logicalBounds.Bottom));
            }

            return(group);
        }
コード例 #19
0
        /// <summary>
        /// Paint a set of reactions.
        /// </summary>
        /// <param name="reactionSet">the reaction to paint</param>
        /// <param name="drawVisitor">the visitor that does the drawing</param>
        /// <param name="bounds">the bounds on the screen</param>
        /// <param name="resetCenter">if true, set the draw center to be the center of bounds</param>
        public void Paint(IReactionSet reactionSet, IDrawVisitor drawVisitor, Rect bounds, bool resetCenter)
        {
            // total up the bounding boxes
            var totalBounds = BoundsCalculator.CalculateBounds(reactionSet);

            this.SetupTransformToFit(bounds, totalBounds, AverageBondLengthCalculator.CalculateAverageBondLength(reactionSet), resetCenter);

            ElementGroup diagram = new ElementGroup();

            foreach (var reaction in reactionSet)
            {
                diagram.Add(reactionRenderer.GenerateDiagram(reaction));
            }

            // paint them all
            this.Paint(drawVisitor, diagram);
        }
コード例 #20
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IAtomContainer container, RendererModel model)
        {
            ElementGroup group = new ElementGroup();

            // TODO : put into RendererModel
            const double ScreenRadius = 2.0;
            Color        RadicalColor = WPF.Media.Colors.Black;

            // XXX : is this the best option?
            double AtomRadius = model.GetAtomRadius() / model.GetScale();

            double modelRadius            = ScreenRadius / model.GetScale();
            double modelSpacing           = modelRadius * 2.5;
            var    singleElectronsPerAtom = new Dictionary <IAtom, int>();

            foreach (var electron in container.SingleElectrons)
            {
                IAtom atom = electron.Atom;
                if (!singleElectronsPerAtom.ContainsKey(atom))
                {
                    singleElectronsPerAtom[atom] = 0;
                }
                Vector2 point  = atom.Point2D.Value;
                int     align  = GeometryUtil.GetBestAlignmentForLabelXY(container, atom);
                var     center = ToPoint(point);
                if (align == 1)
                {
                    center.X += AtomRadius * 4 + singleElectronsPerAtom[atom] * modelSpacing;
                }
                else if (align == -1)
                {
                    center.X -= AtomRadius * 4 + singleElectronsPerAtom[atom] * modelSpacing;
                }
                else if (align == 2)
                {
                    center.Y += AtomRadius * 4 + singleElectronsPerAtom[atom] * modelSpacing;
                }
                else if (align == -2)
                {
                    center.Y -= AtomRadius * 4 + singleElectronsPerAtom[atom] * modelSpacing;
                }
                singleElectronsPerAtom[atom] = singleElectronsPerAtom[atom] + 1;
                group.Add(new OvalElement(center, modelRadius, true, RadicalColor));
            }
            return(group);
        }
コード例 #21
0
ファイル: BasicBondGenerator.cs プロジェクト: qize/NCDK
        /// <summary>
        /// Generate a LineElement or an ElementGroup of LineElements for this bond.
        /// This version should be used if you want to override the type - for
        /// example, for ring double bonds.
        /// </summary>
        /// <param name="bond">the bond to generate for</param>
        /// <param name="type">the type of the bond - single, double, etc</param>
        /// <param name="model">the renderer model</param>
        /// <returns>one or more rendering elements</returns>
        public virtual IRenderingElement GenerateBondElement(IBond bond, BondOrder type, RendererModel model)
        {
            // More than 2 atoms per bond not supported by this module
            if (bond.Atoms.Count > 2)
            {
                return(null);
            }

            // is object right? if not replace with a good one
            Vector2 point1       = bond.Begin.Point2D.Value;
            Vector2 point2       = bond.End.Point2D.Value;
            Color   color        = this.GetColorForBond(bond, model);
            double  bondWidth    = this.GetWidthForBond(bond, model);
            double  bondDistance = model.GetBondDistance() / model.GetScale();

            if (type == BondOrder.Single)
            {
                return(new LineElement(ToPoint(point1), ToPoint(point2), bondWidth, color));
            }
            else
            {
                ElementGroup group = new ElementGroup();
                switch (type)
                {
                case BondOrder.Double:
                    CreateLines(point1, point2, bondWidth, bondDistance, color, group);
                    break;

                case BondOrder.Triple:
                    CreateLines(point1, point2, bondWidth, bondDistance * 2, color, group);
                    group.Add(new LineElement(ToPoint(point1), ToPoint(point2), bondWidth, color));
                    break;

                case BondOrder.Quadruple:
                    CreateLines(point1, point2, bondWidth, bondDistance, color, group);
                    CreateLines(point1, point2, bondWidth, bondDistance * 4, color, group);
                    break;

                default:
                    break;
                }
                return(group);
            }
        }
コード例 #22
0
        /// <inheritdoc/>
        public Rect Paint(IReactionSet reactionSet, IDrawVisitor drawVisitor)
        {
            // total up the bounding boxes
            var totalBounds = BoundsCalculator.CalculateBounds(reactionSet);

            // setup and draw
            this.SetupTransformNatural(totalBounds);

            var diagram = new ElementGroup();

            foreach (var reaction in reactionSet)
            {
                diagram.Add(reactionRenderer.GenerateDiagram(reaction));
            }
            this.Paint(drawVisitor, diagram);

            // the size of the painted diagram is returned
            return(this.ConvertToDiagramBounds(totalBounds));
        }
コード例 #23
0
ファイル: BasicBondGenerator.cs プロジェクト: qize/NCDK
        /// <inheritdoc/>
        public virtual IRenderingElement Generate(IAtomContainer container, RendererModel model)
        {
            ElementGroup group = new ElementGroup();

            this.ringSet = this.GetRingSet(container);

            //Sort the ringSet consistently to ensure consistent rendering.
            //If this is omitted, the bonds may 'tremble'.
            ringSet.Sort(new AtomContainerComparatorBy2DCenter <IRing>());

            foreach (var bond in container.Bonds)
            {
                var bondElement = this.Generate(bond, model);
                if (bondElement != null)
                {
                    group.Add(MarkedElement.MarkupBond(bondElement, bond));
                }
            }
            return(group);
        }
コード例 #24
0
        /// <summary>
        /// Recolor a rendering element after it has been generated. Since rendering elements are
        /// immutable, the input element remains unmodified.
        /// </summary>
        /// <param name="element">the rendering element</param>
        /// <param name="color">the new color</param>
        /// <returns>recolored rendering element</returns>
        private static IRenderingElement Recolor(IRenderingElement element, Color color)
        {
            switch (element)
            {
            case ElementGroup orgGroup:
                var newGroup = new ElementGroup();
                foreach (var child in orgGroup)
                {
                    newGroup.Add(Recolor(child, color));
                }
                return(newGroup);

            case LineElement lineElement:
                return(new LineElement(lineElement.FirstPoint, lineElement.SecondPoint, lineElement.Width, color));

            case GeneralPath generalPath:
                return(generalPath.Recolor(color));
            }
            throw new ArgumentException($"Cannot highlight rendering element, {element.GetType()}");
        }
コード例 #25
0
ファイル: MappingGenerator.cs プロジェクト: nksgw11/NCDK
        /// <inheritdoc/>
        public IRenderingElement Generate(IReaction reaction, RendererModel model)
        {
            if (!model.GetShowAtomAtomMapping())
            {
                return(null);
            }
            var elementGroup = new ElementGroup();
            var mappingColor = model.GetAtomAtomMappingLineColor();

            foreach (var mapping in reaction.Mappings)
            {
                // XXX assume that there are only 2 endpoints!
                // XXX assume that the ChemObjects are actually IAtoms...
                var endPointA = (IAtom)mapping[0];
                var endPointB = (IAtom)mapping[1];
                var pointA    = ToPoint(endPointA.Point2D.Value);
                var pointB    = ToPoint(endPointB.Point2D.Value);
                elementGroup.Add(new LineElement(pointA, pointB, GetWidthForMappingLine(model), mappingColor));
            }
            return(elementGroup);
        }
コード例 #26
0
        /// <inheritdoc/>
        public IRenderingElement Generate(IAtomContainer container, RendererModel parameters)
        {
            if (container.Atoms.Count == 0)
            {
                return(new ElementGroup());
            }

            var symbolRemap = new Dictionary <IAtom, string>();

            StandardSgroupGenerator.PrepareDisplayShortcuts(container, symbolRemap);

            var scale = parameters.GetScale();

            var visibility      = parameters.GetVisibility();
            var coloring        = parameters.GetAtomColorer();
            var annotationColor = parameters.GetAnnotationColor();
            var foreground      = coloring.GetAtomColor(container.Builder.NewAtom("C"));

            // the stroke width is based on the font. a better method is needed to get
            // the exact font stroke but for now we use the width of the pipe character.
            var fontStroke = new TextOutline("|", font, emSize).Resize(1 / scale, 1 / scale).GetBounds().Width;
            var stroke     = parameters.GetStrokeRatio() * fontStroke;

            var annotations = new ElementGroup();

            var donutGenerator = new StandardDonutGenerator(container, font, emSize, parameters, stroke);
            var donuts         = donutGenerator.Generate();

            var symbols = GenerateAtomSymbols(container, symbolRemap,
                                              visibility, parameters,
                                              annotations, foreground,
                                              stroke, donutGenerator);
            var bondElements = StandardBondGenerator.GenerateBonds(container, symbols,
                                                                   parameters, stroke,
                                                                   font, emSize, annotations,
                                                                   donutGenerator);

            var style     = parameters.GetHighlighting();
            var glowWidth = parameters.GetOuterGlowWidth();

            var backLayer   = new ElementGroup();
            var middleLayer = new ElementGroup();
            var frontLayer  = new ElementGroup();

            // bond elements can simply be added to the element group
            for (int i = 0; i < container.Bonds.Count; i++)
            {
                var bond = container.Bonds[i];

                if (IsHidden(bond))
                {
                    continue;
                }

                var highlight = GetHighlightColor(bond, parameters);
                if (highlight != null && style == HighlightStyle.OuterGlow)
                {
                    backLayer.Add(MarkedElement.Markup(OuterGlow(bondElements[i], highlight.Value, glowWidth, stroke), "outerglow"));
                }
                if (highlight != null && style == HighlightStyle.Colored)
                {
                    frontLayer.Add(MarkedElement.MarkupBond(Recolor(bondElements[i], highlight.Value), bond));
                }
                else
                {
                    middleLayer.Add(MarkedElement.MarkupBond(bondElements[i], bond));
                }
            }

            // bonds for delocalised aromatic
            frontLayer.Add(donuts);

            // convert the atom symbols to IRenderingElements
            for (int i = 0; i < container.Atoms.Count; i++)
            {
                var atom = container.Atoms[i];

                if (IsHidden(atom))
                {
                    continue;
                }

                var highlight = GetHighlightColor(atom, parameters);
                var color     = GetColorOfAtom(symbolRemap, coloring, foreground, style, atom, highlight);

                if (symbols[i] == null)
                {
                    // we add a 'ball' around atoms with no symbols (e.g. carbons)
                    if (highlight != null && style == HighlightStyle.OuterGlow)
                    {
                        backLayer.Add(MarkedElement.Markup(new OvalElement(ToPoint(atom.Point2D.Value), 1.75 * glowWidth * stroke, true, highlight.Value), "outerglow"));
                    }
                    continue;
                }

                var symbolElements = new ElementGroup();
                foreach (var shape in symbols[i].GetOutlines())
                {
                    GeneralPath path = GeneralPath.ShapeOf(shape, color);
                    symbolElements.Add(path);
                }

                // add the annotations of the symbol to the annotations ElementGroup
                foreach (var shape in symbols[i].GetAnnotationOutlines())
                {
                    annotations.Add(MarkedElement.Markup(GeneralPath.ShapeOf(shape, annotationColor), "annotation"));
                }

                if (highlight != null && style == HighlightStyle.OuterGlow)
                {
                    backLayer.Add(MarkedElement.Markup(OuterGlow(symbolElements, highlight.Value, glowWidth, stroke), "outerglow"));
                }

                if (highlight != null && style == HighlightStyle.Colored)
                {
                    frontLayer.Add(MarkedElement.MarkupAtom(symbolElements, atom));
                }
                else
                {
                    middleLayer.Add(MarkedElement.MarkupAtom(symbolElements, atom));
                }
            }

            // Add the Sgroups display elements to the front layer
            var sgroups = StandardSgroupGenerator.Generate(parameters, stroke, font, emSize, foreground, atomGenerator, symbols, container);

            frontLayer.Add(sgroups);

            // Annotations are added to the front layer.
            frontLayer.Add(annotations);

            var group = new ElementGroup
            {
                backLayer,
                middleLayer,
                frontLayer
            };

            return(MarkedElement.MarkupMol(group, container));
        }
コード例 #27
0
        /// <summary>
        /// Generate the intermediate <see cref="AtomSymbol"/> instances.
        /// </summary>
        /// <param name="container">structure representation</param>
        /// <param name="symbolRemap">use alternate symbols (used for Sgroup shortcuts)</param>
        /// <param name="visibility">defines whether an atom symbol is displayed</param>
        /// <param name="parameters">render model parameters</param>
        /// <returns>generated atom symbols (can contain <see langword="null"/>)</returns>
        private AtomSymbol[] GenerateAtomSymbols(IAtomContainer container,
                                                 Dictionary <IAtom, string> symbolRemap,
                                                 SymbolVisibility visibility,
                                                 RendererModel parameters,
                                                 ElementGroup annotations,
                                                 Color foreground,
                                                 double stroke,
                                                 StandardDonutGenerator donutGen)
        {
            var scale      = parameters.GetScale();
            var annDist    = parameters.GetAnnotationDistance() * (parameters.GetBondLength() / scale);
            var annScale   = (1 / scale) * parameters.GetAnnotationFontScale();
            var annColor   = parameters.GetAnnotationColor();
            var halfStroke = stroke / 2;

            var symbols = new AtomSymbol[container.Atoms.Count];
            var builder = container.Builder;

            // check if we should annotate attachment point numbers (maxAttach>1)
            // and queue them all up for processing
            var attachPoints = new List <IPseudoAtom>();
            int maxAttach    = 0;

            for (int i = 0; i < container.Atoms.Count; i++)
            {
                var atom = container.Atoms[i];

                if (IsHiddenFully(atom))
                {
                    continue;
                }

                if (atom is IPseudoAtom)
                {
                    var attachNum = ((IPseudoAtom)atom).AttachPointNum;
                    if (attachNum > 0)
                    {
                        attachPoints.Add((IPseudoAtom)atom);
                    }
                    if (attachNum > maxAttach)
                    {
                        maxAttach = attachNum;
                    }
                }

                var remapped     = symbolRemap.ContainsKey(atom);
                var bonds        = container.GetConnectedBonds(atom);
                var neighbors    = container.GetConnectedAtoms(atom);
                var visNeighbors = new List <IAtom>();

                // if a symbol is remapped we only want to consider
                // visible neighbors in the alignment calculation, otherwise
                // we include all neighbors
                foreach (var neighbor in neighbors)
                {
                    if (!remapped || !IsHidden(neighbor))
                    {
                        visNeighbors.Add(neighbor);
                    }
                }

                var auxVectors = new List <Vector2>(1);

                // only generate if the symbol is visible
                if (visibility.Visible(atom, bonds, parameters) || remapped)
                {
                    var hPosition = HydrogenPositionTools.Position(atom, visNeighbors);

                    if (atom.ImplicitHydrogenCount != null && atom.ImplicitHydrogenCount > 0)
                    {
                        auxVectors.Add(hPosition.Vector());
                    }

                    if (remapped)
                    {
                        symbols[i] = atomGenerator.GenerateAbbreviatedSymbol(symbolRemap[atom], hPosition);
                    }
                    else if (donutGen.IsChargeDelocalised(atom))
                    {
                        var charge = atom.FormalCharge;
                        atom.FormalCharge = 0;
                        // can't think of a better way to handle this without API
                        // change to symbol visibility
                        if (atom.AtomicNumber != 6)
                        {
                            symbols[i] = atomGenerator.GenerateSymbol(container, atom, hPosition, parameters);
                        }
                        atom.FormalCharge = charge;
                    }
                    else
                    {
                        symbols[i] = atomGenerator.GenerateSymbol(container, atom, hPosition, parameters);
                    }

                    if (symbols[i] != null)
                    {
                        // defines how the element is aligned on the atom point, when
                        // aligned to the left, the first character 'e.g. Cl' is used.
                        if (visNeighbors.Count < 4)
                        {
                            if (hPosition == HydrogenPosition.Left)
                            {
                                symbols[i] = symbols[i].AlignTo(AtomSymbol.SymbolAlignment.Right);
                            }
                            else
                            {
                                symbols[i] = symbols[i].AlignTo(AtomSymbol.SymbolAlignment.Left);
                            }
                        }

                        var p = atom.Point2D;

                        if (p == null)
                        {
                            throw new ArgumentException("Atom did not have 2D coordinates");
                        }

                        symbols[i] = symbols[i].Resize(1 / scale, 1 / -scale).Center(p.Value.X, p.Value.Y);
                    }
                }

                var label = GetAnnotationLabel(atom);

                if (label != null)
                {
                    // to ensure consistent draw distance we need to adjust the annotation distance
                    // depending on whether we are drawing next to an atom symbol or not.
                    double strokeAdjust = symbols[i] != null ? -halfStroke : 0;

                    var vector     = NewAtomAnnotationVector(atom, bonds, auxVectors);
                    var annOutline = GenerateAnnotation(atom.Point2D.Value, label, vector, annDist + strokeAdjust, annScale, font, emSize, symbols[i]);

                    // the AtomSymbol may migrate during bond generation and therefore the annotation
                    // needs to be tied to the symbol. If no symbol is available the annotation is
                    // fixed and we can add it to the annotation ElementGroup right away.
                    if (symbols[i] != null)
                    {
                        symbols[i] = symbols[i].AddAnnotation(annOutline);
                    }
                    else
                    {
                        annotations.Add(GeneralPath.ShapeOf(annOutline.GetOutline(), annColor));
                    }
                }
            }

            // label attachment points
            if (maxAttach > 1)
            {
                var    attachNumOutlines = new List <TextOutline>();
                double maxRadius         = 0;

                foreach (IPseudoAtom atom in attachPoints)
                {
                    int attachNum = atom.AttachPointNum;

                    // to ensure consistent draw distance we need to adjust the annotation distance
                    // depending on whether we are drawing next to an atom symbol or not.
                    var strokeAdjust = -halfStroke;

                    var vector = NewAttachPointAnnotationVector(
                        atom,
                        container.GetConnectedBonds(atom),
                        new List <Vector2>());

                    var outline = GenerateAnnotation(atom.Point2D.Value,
                                                     attachNum.ToString(),
                                                     vector,
                                                     1.75 * annDist + strokeAdjust,
                                                     annScale,
                                                     new Typeface(font.FontFamily, font.Style, WPF.FontWeights.Bold, font.Stretch),
                                                     emSize,
                                                     null);

                    attachNumOutlines.Add(outline);

                    var w = outline.GetBounds().Width;
                    var h = outline.GetBounds().Height;
                    var r = Math.Sqrt(w * w + h * h) / 2;
                    if (r > maxRadius)
                    {
                        maxRadius = r;
                    }
                }

                foreach (var outline in attachNumOutlines)
                {
                    var group  = new ElementGroup();
                    var radius = 2 * stroke + maxRadius;
                    var shape  = new EllipseGeometry(outline.GetCenter(), radius, radius);
                    var area1  = Geometry.Combine(shape, outline.GetOutline(), GeometryCombineMode.Exclude, Transform.Identity);
                    group.Add(GeneralPath.ShapeOf(area1, foreground));
                    annotations.Add(group);
                }
            }

            return(symbols);
        }
コード例 #28
0
        private IRenderingElement GenerateSgroupBrackets(Sgroup sgroup,
                                                         IList <SgroupBracket> brackets,
                                                         IReadOnlyDictionary <IAtom, AtomSymbol> symbols,
                                                         string subscriptSuffix,
                                                         string superscriptSuffix)
        {
            // brackets are square by default (style:0)
            var  style  = (int?)sgroup.GetValue(SgroupKey.CtabBracketStyle);
            bool round  = style != null && style == 1;
            var  result = new ElementGroup();

            var atoms         = sgroup.Atoms;
            var crossingBonds = sgroup.Bonds;

            // easy to depict in correct orientation, we just
            // point each bracket at the atom of a crossing
            // bond that is 'in' the group - this scales
            // to more than two brackets

            // first we need to pair the brackets with the bonds
            var pairs = crossingBonds.Count == brackets.Count ? BracketBondPairs(brackets, crossingBonds) : Dictionaries.Empty <SgroupBracket, IBond>();

            // override bracket layout around single atoms to bring them in closer
            if (atoms.Count == 1)
            {
                var atom = atoms.First();

                // e.g. 2 HCL, 8 H2O etc.
                if (IsUnsignedInt(subscriptSuffix) &&
                    !crossingBonds.Any() &&
                    symbols.ContainsKey(atom))
                {
                    var prefix       = new TextOutline('·' + subscriptSuffix, font, emSize).Resize(1 / scale, 1 / -scale);
                    var prefixBounds = prefix.LogicalBounds;

                    var symbol = symbols[atom];

                    var bounds = symbol.GetConvexHull().Outline.Bounds;

                    // make slightly large
                    bounds = new Rect(bounds.Bottom - 2 * stroke,
                                      bounds.Left - 2 * stroke,
                                      bounds.Width + 4 * stroke,
                                      bounds.Height + 4 * stroke);

                    prefix = prefix.Translate(bounds.Bottom - prefixBounds.Top,
                                              symbol.GetAlignmentCenter().Y - prefixBounds.CenterY());

                    result.Add(GeneralPath.ShapeOf(prefix.GetOutline(), foreground));
                }
                // e.g. CC(O)nCC
                else if (crossingBonds.Count > 0)
                {
                    var scriptscale = labelScale;

                    var leftBracket  = new TextOutline("(", font, emSize).Resize(1 / scale, 1 / -scale);
                    var rightBracket = new TextOutline(")", font, emSize).Resize(1 / scale, 1 / -scale);

                    var leftCenter  = leftBracket.GetCenter();
                    var rightCenter = rightBracket.GetCenter();

                    if (symbols.ContainsKey(atom))
                    {
                        var symbol = symbols[atom];

                        var bounds = symbol.GetConvexHull().Outline.Bounds;
                        // make slightly large
                        bounds = new Rect(bounds.Left - 2 * stroke,
                                          bounds.Top - 2 * stroke,
                                          bounds.Width + 4 * stroke,
                                          bounds.Height + 4 * stroke);

                        leftBracket = leftBracket.Translate(bounds.Left - 0.1 - leftCenter.X,
                                                            symbol.GetAlignmentCenter().Y - leftCenter.Y);
                        rightBracket = rightBracket.Translate(bounds.Right + 0.1 - rightCenter.X,
                                                              symbol.GetAlignmentCenter().Y - rightCenter.Y);
                    }
                    else
                    {
                        var p = atoms.First().Point2D.Value;
                        leftBracket  = leftBracket.Translate(p.X - 0.2 - leftCenter.X, p.Y - leftCenter.Y);
                        rightBracket = rightBracket.Translate(p.X + 0.2 - rightCenter.X, p.Y - rightCenter.Y);
                    }

                    result.Add(GeneralPath.ShapeOf(leftBracket.GetOutline(), foreground));
                    result.Add(GeneralPath.ShapeOf(rightBracket.GetOutline(), foreground));

                    var rightBracketBounds = rightBracket.GetBounds();

                    // subscript/superscript suffix annotation
                    if (subscriptSuffix != null && subscriptSuffix.Any())
                    {
                        TextOutline subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(),
                                                                          new Vector2(rightBracketBounds.Right,
                                                                                      rightBracketBounds.Top - 0.1),
                                                                          new Vector2(-0.5 * rightBracketBounds.Width, 0),
                                                                          scriptscale));
                        result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                    }
                    if (superscriptSuffix != null && superscriptSuffix.Any())
                    {
                        var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(),
                                                                    new Vector2(rightBracketBounds.Right,
                                                                                rightBracketBounds.Bottom + 0.1),
                                                                    new Vector2(-rightBracketBounds.Width, 0),
                                                                    scriptscale));
                        result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                    }
                }
            }
            else if (pairs.Any())
            {
                SgroupBracket suffixBracket     = null;
                Vector2?      suffixBracketPerp = null;

                foreach (var e in pairs)
                {
                    var bracket     = e.Key;
                    var bond        = e.Value;
                    var inGroupAtom = atoms.Contains(bond.Begin) ? bond.Begin : bond.End;

                    var p1 = bracket.FirstPoint;
                    var p2 = bracket.SecondPoint;

                    var perp = VecmathUtil.NewPerpendicularVector(VecmathUtil.NewUnitVector(p1, p2));

                    // point the vector at the atom group
                    var midpoint = VecmathUtil.Midpoint(p1, p2);
                    if (Vector2.Dot(perp, VecmathUtil.NewUnitVector(midpoint, inGroupAtom.Point2D.Value)) < 0)
                    {
                        perp = Vector2.Negate(perp);
                    }
                    perp *= bracketDepth;

                    if (round)
                    {
                        result.Add(CreateRoundBracket(p1, p2, perp, midpoint));
                    }
                    else
                    {
                        result.Add(CreateSquareBracket(p1, p2, perp));
                    }

                    if (suffixBracket == null)
                    {
                        suffixBracket     = bracket;
                        suffixBracketPerp = perp;
                    }
                    else
                    {
                        // is this bracket better as a suffix?
                        var sp1      = suffixBracket.FirstPoint;
                        var sp2      = suffixBracket.SecondPoint;
                        var bestMaxX = Math.Max(sp1.X, sp2.X);
                        var thisMaxX = Math.Max(p1.X, p2.X);
                        var bestMaxY = Math.Max(sp1.Y, sp2.Y);
                        var thisMaxY = Math.Max(p1.Y, p2.Y);

                        // choose the most eastern or.. the most southern
                        var xDiff = thisMaxX - bestMaxX;
                        var yDiff = thisMaxY - bestMaxY;
                        if (xDiff > EQUIV_THRESHOLD || (xDiff > -EQUIV_THRESHOLD && yDiff < -EQUIV_THRESHOLD))
                        {
                            suffixBracket     = bracket;
                            suffixBracketPerp = perp;
                        }
                    }
                }

                // write the labels
                if (suffixBracket != null)
                {
                    var subSufPnt = suffixBracket.FirstPoint;
                    var supSufPnt = suffixBracket.SecondPoint;

                    // try to put the subscript on the bottom
                    var xDiff = subSufPnt.X - supSufPnt.X;
                    var yDiff = subSufPnt.Y - supSufPnt.Y;
                    if (yDiff > EQUIV_THRESHOLD || (yDiff > -EQUIV_THRESHOLD && xDiff > EQUIV_THRESHOLD))
                    {
                        var tmpP = subSufPnt;
                        subSufPnt = supSufPnt;
                        supSufPnt = tmpP;
                    }

                    // subscript/superscript suffix annotation
                    if (subscriptSuffix != null && subscriptSuffix.Any())
                    {
                        var subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(), subSufPnt, suffixBracketPerp.Value, labelScale));
                        result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                    }
                    if (superscriptSuffix != null && superscriptSuffix.Any())
                    {
                        var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(), supSufPnt, suffixBracketPerp.Value, labelScale));
                        result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                    }
                }
            }
            else if (brackets.Count == 2)
            {
                var b1p1 = brackets[0].FirstPoint;
                var b1p2 = brackets[0].SecondPoint;
                var b2p1 = brackets[1].FirstPoint;
                var b2p2 = brackets[1].SecondPoint;

                var b1vec = VecmathUtil.NewUnitVector(b1p1, b1p2);
                var b2vec = VecmathUtil.NewUnitVector(b2p1, b2p2);

                var b1pvec = VecmathUtil.NewPerpendicularVector(b1vec);
                var b2pvec = VecmathUtil.NewPerpendicularVector(b2vec);

                // Point the vectors at each other
                if (Vector2.Dot(b1pvec, VecmathUtil.NewUnitVector(b1p1, b2p1)) < 0)
                {
                    b1pvec = Vector2.Negate(b1pvec);
                }
                if (Vector2.Dot(b2pvec, VecmathUtil.NewUnitVector(b2p1, b1p1)) < 0)
                {
                    b2pvec = Vector2.Negate(b2pvec);
                }

                // scale perpendicular vectors by how deep the brackets need to be
                b1pvec *= bracketDepth;
                b2pvec *= bracketDepth;

                // bad brackets
                if (double.IsNaN(b1pvec.X) || double.IsNaN(b1pvec.Y) ||
                    double.IsNaN(b2pvec.X) || double.IsNaN(b2pvec.Y))
                {
                    return(result);
                }

                {
                    var path = new PathGeometry();

                    if (round)
                    {
                        {
                            // bracket 1 (cp: control point)
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b1p1.X + b1pvec.X, b1p1.Y + b1pvec.Y)
                            };
                            Vector2 cpb1 = VecmathUtil.Midpoint(b1p1, b1p2);
                            cpb1 += VecmathUtil.Negate(b1pvec);
                            var seg = new QuadraticBezierSegment
                            {
                                Point1 = new Point(cpb1.X, cpb1.Y),
                                Point2 = new Point(b1p2.X + b1pvec.X, b1p2.Y + b1pvec.Y)
                            };
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }

                        {
                            // bracket 2 (cp: control point)
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b2p1.X + b2pvec.X, b2p1.Y + b2pvec.Y)
                            };
                            var cpb2 = VecmathUtil.Midpoint(b2p1, b2p2);
                            cpb2 += VecmathUtil.Negate(b2pvec);
                            var seg = new QuadraticBezierSegment
                            {
                                Point1 = new Point(cpb2.X, cpb2.Y),
                                Point2 = new Point(b2p2.X + b2pvec.X, b2p2.Y + b2pvec.Y)
                            };
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }
                    }
                    else
                    {
                        {
                            // bracket 1
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b1p1.X + b1pvec.X, b1p1.Y + b1pvec.Y)
                            };
                            var seg = new PolyLineSegment();
                            seg.Points.Add(new Point(b1p1.X, b1p1.Y));
                            seg.Points.Add(new Point(b1p2.X, b1p2.Y));
                            seg.Points.Add(new Point(b1p2.X + b1pvec.X, b1p2.Y + b1pvec.Y));
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }

                        {
                            // bracket 2
                            var pf = new PathFigure
                            {
                                StartPoint = new Point(b2p1.X + b2pvec.X, b2p1.Y + b2pvec.Y)
                            };
                            var seg = new PolyLineSegment();
                            seg.Points.Add(new Point(b2p1.X, b2p1.Y));
                            seg.Points.Add(new Point(b2p2.X, b2p2.Y));
                            seg.Points.Add(new Point(b2p2.X + b2pvec.X, b2p2.Y + b2pvec.Y));
                            pf.Segments.Add(seg);
                            path.Figures.Add(pf);
                        }
                    }

                    result.Add(GeneralPath.OutlineOf(path, stroke, foreground));
                }

                // work out where to put the suffix labels (e.g. ht/hh/eu) superscript
                // and (e.g. n, xl, c, mix) subscript
                // TODO: could be improved
                var b1MaxX = Math.Max(b1p1.X, b1p2.X);
                var b2MaxX = Math.Max(b2p1.X, b2p2.X);
                var b1MaxY = Math.Max(b1p1.Y, b1p2.Y);
                var b2MaxY = Math.Max(b2p1.Y, b2p2.Y);

                var subSufPnt = b2p2;
                var supSufPnt = b2p1;
                var subpvec   = b2pvec;

                var bXDiff = b1MaxX - b2MaxX;
                var bYDiff = b1MaxY - b2MaxY;

                if (bXDiff > EQUIV_THRESHOLD || (bXDiff > -EQUIV_THRESHOLD && bYDiff < -EQUIV_THRESHOLD))
                {
                    subSufPnt = b1p2;
                    supSufPnt = b1p1;
                    subpvec   = b1pvec;
                }

                var xDiff = subSufPnt.X - supSufPnt.X;
                var yDiff = subSufPnt.Y - supSufPnt.Y;

                if (yDiff > EQUIV_THRESHOLD || (yDiff > -EQUIV_THRESHOLD && xDiff > EQUIV_THRESHOLD))
                {
                    var tmpP = subSufPnt;
                    subSufPnt = supSufPnt;
                    supSufPnt = tmpP;
                }

                // subscript/superscript suffix annotation
                if (subscriptSuffix != null && subscriptSuffix.Any())
                {
                    var subscriptOutline = LeftAlign(MakeText(subscriptSuffix.ToLowerInvariant(), subSufPnt, subpvec, labelScale));
                    result.Add(GeneralPath.ShapeOf(subscriptOutline.GetOutline(), foreground));
                }
                if (superscriptSuffix != null && superscriptSuffix.Any())
                {
                    var superscriptOutline = LeftAlign(MakeText(superscriptSuffix.ToLowerInvariant(), supSufPnt, subpvec, labelScale));
                    result.Add(GeneralPath.ShapeOf(superscriptOutline.GetOutline(), foreground));
                }
            }
            return(result);
        }
コード例 #29
0
        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));
            }
        }
コード例 #30
0
ファイル: StandardDonutGenerator.cs プロジェクト: qize/NCDK
        public IRenderingElement Generate()
        {
            if (!delocalisedDonuts)
            {
                return(null);
            }
            var group = new ElementGroup();

            smallest = Cycles.EdgeShort.Find(mol).ToRingSet();
            foreach (var ring in smallest)
            {
                if (!CanDelocalise(ring))
                {
                    continue;
                }
                foreach (var bond in ring.Bonds)
                {
                    bonds.Add(bond);
                }
                int charge   = 0;
                int unpaired = 0;
                foreach (var atom in ring.Atoms)
                {
                    var q = atom.FormalCharge ?? 0;
                    if (q == 0)
                    {
                        continue;
                    }
                    int nCyclic = 0;
                    foreach (var bond in mol.GetConnectedBonds(atom))
                    {
                        if (bond.IsInRing)
                        {
                            nCyclic++;
                        }
                    }
                    if (nCyclic > 2)
                    {
                        continue;
                    }
                    atoms.Add(atom);
                    charge += q;
                }
                var p2 = GeometryUtil.Get2DCenter(ring);

                if (charge != 0)
                {
                    var qText = charge < 0 ? "–" : "+";
                    if (charge < -1)
                    {
                        qText = Math.Abs(charge) + qText;
                    }
                    else if (charge > +1)
                    {
                        qText = Math.Abs(charge) + qText;
                    }

                    TextOutline qSym = new TextOutline(qText, font, emSize);
                    qSym = qSym.Resize(1 / scale, -1 / scale);
                    qSym = qSym.Translate(p2.X - qSym.GetCenter().X,
                                          p2.Y - qSym.GetCenter().Y);
                    group.Add(GeneralPath.ShapeOf(qSym.GetOutline(), fgColor));
                }

                double s = GeometryUtil.GetBondLengthMedian(ring);
                double n = ring.Bonds.Count;
                double r = s / (2 * Math.Tan(Math.PI / n));
                group.Add(new OvalElement(new WPF::Point(p2.X, p2.Y), r - 1.5 * dbSpacing,
                                          stroke, false, fgColor));
            }
            return(group);
        }