Пример #1
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()}");
            }
        }
Пример #2
0
        //    public Rectangle PaintReactionSet(
        //            IReactionSet reactionSet, IDrawVisitor drawVisitor) {
        //        // total up the bounding boxes
        //        Rectangle2D totalBounds = CreateRectangle();
        //        foreach (var reaction in reactionSet.reactions()) {
        //            Rectangle2D modelBounds = BoundsCalculator.CalculateBounds(reaction);
        //            if (totalBounds == null) {
        //                totalBounds = modelBounds;
        //            } else {
        //                totalBounds = totalBounds.CreateUnion(modelBounds);
        //            }
        //        }
        //
        //        // setup and draw
        //        this.SetupTransformNatural(totalBounds);
        //        ElementGroup diagram = new ElementGroup();
        //        foreach (var reaction in reactionSet.reactions()) {
        //            diagram.Add(this.GenerateDiagram(reaction));
        //        }
        //        this.Paint(drawVisitor, diagram);
        //
        //        // the size of the painted diagram is returned
        //        return this.ConvertToDiagramBounds(totalBounds);
        //    }
        //
        //    public Rectangle PaintReaction(
        //            IReaction reaction, IDrawVisitor drawVisitor) {
        //
        //        // calculate the bounds
        //        Rectangle2D modelBounds = BoundsCalculator.CalculateBounds(reaction);
        //
        //        // setup and draw
        //        this.SetupTransformNatural(modelBounds);
        //        IRenderingElement diagram = this.GenerateDiagram(reaction);
        //        this.Paint(drawVisitor, diagram);
        //
        //        return this.ConvertToDiagramBounds(modelBounds);
        //    }

        /// <summary>
        /// Paint a ChemModel.
        /// </summary>
        /// <param name="chemModel"></param>
        /// <param name="drawVisitor">the visitor that does the drawing</param>
        /// <param name="bounds">the bounds of the area to paint on.</param>
        /// <param name="resetCenter">if true, set the modelCenter to the center of the ChemModel's bounds.</param>
        public void Paint(IChemModel chemModel, IDrawVisitor drawVisitor, Rect bounds, bool resetCenter)
        {
            // check for an empty model
            var          moleculeSet = chemModel.MoleculeSet;
            IReactionSet reactionSet = chemModel.ReactionSet;

            // nasty, but it seems that reactions can be read in as ChemModels
            // with BOTH a ReactionSet AND a MoleculeSet...
            if (moleculeSet == null || reactionSet != null)
            {
                if (reactionSet != null)
                {
                    reactionSetRenderer.Paint(reactionSet, drawVisitor, bounds, resetCenter);
                }
                return;
            }

            // calculate the total bounding box
            var modelBounds = BoundsCalculator.CalculateBounds(moleculeSet);

            this.SetupTransformToFit(bounds, modelBounds,
                                     AverageBondLengthCalculator.CalculateAverageBondLength(chemModel), resetCenter);

            // generate the elements
            IRenderingElement diagram = moleculeSetRenderer.GenerateDiagram(moleculeSet);

            // paint it
            this.Paint(drawVisitor, diagram);
        }
Пример #3
0
 public IReadOnlyList <IRenderingElement> GetAllSimpleElements(IRenderingElement root)
 {
     elements.Clear();
     getElementGroups = false;
     root.Accept(this);
     return(new List <IRenderingElement>(elements));
 }
Пример #4
0
        private IRenderingElement GenerateStereoElement(IBond bond, RendererModel model)
        {
            BondStereo stereo = bond.Stereo;

            WedgeLineElement.WedgeType type = WedgeLineElement.WedgeType.Wedged;
            BondDirection dir = BondDirection.ToSecond;

            switch (stereo)
            {
            case BondStereo.Down:
            case BondStereo.DownInverted:
                type = WedgeLineElement.WedgeType.Dashed;
                break;

            case BondStereo.UpOrDown:
            case BondStereo.UpOrDownInverted:
                type = WedgeLineElement.WedgeType.Indiff;
                break;
            }
            switch (stereo)
            {
            case BondStereo.DownInverted:
            case BondStereo.UpInverted:
            case BondStereo.UpOrDownInverted:
                dir = BondDirection.ToFirst;
                break;
            }

            IRenderingElement base_ = GenerateBondElement(bond, BondOrder.Single, model);

            return(new WedgeLineElement((LineElement)base_, type, dir, GetColorForBond(bond, model)));
        }
Пример #5
0
 static IRenderingElement Unbox(IRenderingElement element)
 {
     if (element is MarkedElement)
     {
         return(((MarkedElement)element).Element());
     }
     return(element);
 }
Пример #6
0
        /// <summary>
        /// Markup a molecule with the class <paramref name="mol"/> and optionally the ids/classes
        /// from it's properties.
        /// </summary>
        /// <param name="elem">rendering element</param>
        /// <param name="mol">molecule</param>
        /// <returns>the marked element</returns>
        public static MarkedElement MarkupMol(IRenderingElement elem, IAtomContainer mol)
        {
            Debug.Assert(elem != null);
            var tagElem = MarkupChemObj(elem, mol);

            tagElem.AddClass("mol");
            return(tagElem);
        }
Пример #7
0
        public void Visit(IRenderingElement element, Transform transform)
        {
            var save = transform;

            this.transform = transform;
            Visit(element);
            transform = save;
        }
Пример #8
0
        public void Main()
        {
            IRenderingElement renderingElements = null;

            #region
            SvgDrawVisitor visitor = new SvgDrawVisitor(50, 50, Depiction.UnitsMM);
            visitor.Visit(renderingElements);
            string svg = visitor.ToString();
            #endregion
        }
Пример #9
0
        public virtual void TestSingleAtom()
        {
            IAtomContainer singleAtom = MakeSingleAtom();

            // nothing should be made
            IRenderingElement root = generator.Generate(singleAtom, singleAtom.Atoms[0], model);
            var elements           = elementUtil.GetAllSimpleElements(root);

            Assert.AreEqual(1, elements.Count);
        }
Пример #10
0
        /// <summary>
        /// Given a rendering element, traverse the elements compute required bounds
        /// to full display all elements. The method searches for <see cref="Bounds"/>
        /// elements which act to specify the required bounds when adjunct labels
        /// are considered.
        /// </summary>
        /// <param name="element">a rendering element</param>
        /// <returns>the bounds required (<see cref="Rect.Empty"/> if unspecified)</returns>
        public virtual Rect GetBounds(IRenderingElement element)
        {
            if (element == null)
            {
                return(Rect.Empty);
            }
            var bounds = new Bounds(element);

            return(new Rect(bounds.MinX, bounds.MinY,
                            bounds.Width, bounds.Height));
        }
Пример #11
0
        /// <summary>
        /// Markup a bond with the class 'bond' and optionally the ids/classes
        /// from it's properties.
        /// </summary>
        /// <param name="elem">rendering element</param>
        /// <param name="bond">bond</param>
        /// <returns>the marked element</returns>
        public static MarkedElement MarkupBond(IRenderingElement elem, IBond bond)
        {
            if (elem == null)
            {
                throw new ArgumentNullException(nameof(elem));
            }
            var tagElem = MarkupChemObj(elem, bond);

            tagElem.AddClass("bond");
            return(tagElem);
        }
Пример #12
0
        /// <summary>
        /// Markup a atom with the class 'atom' and optionally the ids/classes
        /// from it's properties.
        /// </summary>
        /// <param name="elem">rendering element</param>
        /// <param name="atom">atom</param>
        /// <returns>the marked element</returns>
        public static MarkedElement MarkupAtom(IRenderingElement elem, IAtom atom)
        {
            if (elem == null)
            {
                return(null);
            }
            var tagElem = MarkupChemObj(elem, atom);

            tagElem.AddClass("atom");
            return(tagElem);
        }
Пример #13
0
        /// <summary>
        /// Markup a rendering element with the specified classes.
        /// </summary>
        /// <param name="elem">rendering element</param>
        /// <param name="classes">classes</param>
        /// <returns>the marked element</returns>
        public static MarkedElement Markup(IRenderingElement elem, params string[] classes)
        {
            Debug.Assert(elem != null);
            var tagElem = new MarkedElement(elem);

            foreach (var cls in classes)
            {
                tagElem.AddClass(cls);
            }
            return(tagElem);
        }
Пример #14
0
        private void Traverse(IRenderingElement newElement)
        {
            var stack = new Deque <IRenderingElement>();

            stack.Push(newElement);
            while (stack.Any())
            {
                var element = stack.Poll();
                switch (element)
                {
                case Bounds e:
                    Add(e);
                    break;

                case GeneralPath e:
                    Add(e);
                    break;

                case LineElement lineElem:
                    var vec   = lineElem.SecondPoint - lineElem.FirstPoint;
                    var ortho = new WPF::Vector(-vec.Y, vec.X);
                    ortho.Normalize();
                    vec.Normalize();
                    ortho *= lineElem.Width / 2;      // stroke width
                    vec   *= lineElem.Width / 2;      // stroke rounded also makes line longer
                    Add(lineElem.FirstPoint - vec + ortho);
                    Add(lineElem.SecondPoint + vec + ortho);
                    Add(lineElem.FirstPoint - vec - ortho);
                    Add(lineElem.SecondPoint + vec - ortho);
                    break;

                case OvalElement oval:
                    Add(new Point(oval.Coord.X - oval.Radius, oval.Coord.Y));
                    Add(new Point(oval.Coord.X + oval.Radius, oval.Coord.Y));
                    Add(new Point(oval.Coord.X, oval.Coord.Y - oval.Radius));
                    Add(new Point(oval.Coord.X, oval.Coord.Y + oval.Radius));
                    break;

                case ElementGroup elementGroup:
                    stack.AddRange(elementGroup);
                    break;

                case MarkedElement e:
                    stack.Add(e.Element());
                    break;

                default:
                    // ignored from bounds calculation, we don't really
                    // care but log we skipped it
                    Trace.TraceWarning($"{element.GetType()} not included in bounds calculation");
                    break;
                }
            }
        }
Пример #15
0
        /// <summary>
        /// Paint a set of molecules.
        /// </summary>
        /// <param name="molecules">the <see cref="IChemObjectSet{T}"/> 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(IChemObjectSet <IAtomContainer> molecules, IDrawVisitor drawVisitor, Rect bounds, bool resetCenter)
        {
            // total up the bounding boxes
            var totalBounds = BoundsCalculator.CalculateBounds(molecules);

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

            IRenderingElement diagram = this.GenerateDiagram(molecules);

            this.Paint(drawVisitor, diagram);
        }
Пример #16
0
        private static MarkedElement MarkupChemObj(IRenderingElement elem, IChemObject chemObj)
        {
            Debug.Assert(elem != null);
            var tagElem = new MarkedElement(elem);

            if (chemObj != null)
            {
                tagElem.Id = chemObj.GetProperty <string>(IdKey);
                tagElem.AddClass(chemObj.GetProperty <string>(ClassKey));
            }
            return(tagElem);
        }
Пример #17
0
        /// <inheritdoc/>
        public Rect Paint(IAtomContainer atomContainer, IDrawVisitor drawVisitor)
        {
            // the bounds of the model
            var modelBounds = BoundsCalculator.CalculateBounds(atomContainer);

            // setup and draw
            this.SetupTransformNatural(modelBounds);
            IRenderingElement diagram = GenerateDiagram(atomContainer);

            this.Paint(drawVisitor, diagram);

            return(this.ConvertToDiagramBounds(modelBounds));
        }
Пример #18
0
        /// <inheritdoc/>
        public Rect Paint(IChemObjectSet <IAtomContainer> moleculeSet, IDrawVisitor drawVisitor)
        {
            // total up the bounding boxes
            var totalBounds = BoundsCalculator.CalculateBounds(moleculeSet);

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

            IRenderingElement diagram = this.GenerateDiagram(moleculeSet);

            this.Paint(drawVisitor, diagram);

            return(this.ConvertToDiagramBounds(totalBounds));
        }
Пример #19
0
        public virtual void TestSquare()
        {
            IAtomContainer square = MakeSquare();

            model.SetKekuleStructure(true);

            // generate all four atoms
            IRenderingElement root = generator.Generate(square, model);
            var elements           = elementUtil.GetAllSimpleElements(root);

            Assert.AreEqual(4, elements.Count);

            // test that the center is at the origin
            Assert.AreEqual(new Point(0, 0), Center(elements));
        }
Пример #20
0
        /// <summary>
        /// The target method for paintChemModel, paintReaction, and paintMolecule.
        /// </summary>
        /// <param name="drawVisitor">the visitor to draw with</param>
        /// <param name="diagram">the IRenderingElement tree to render</param>
        protected virtual void Paint(IDrawVisitor drawVisitor, IRenderingElement diagram)
        {
            if (diagram == null)
            {
                return;
            }

            // cache the diagram for quick-redraw
            this.cachedDiagram = diagram;

            fontManager.FontName   = rendererModel.GetFontName();
            fontManager.FontWeight = rendererModel.GetUsedFontStyle();

            drawVisitor.FontManager   = this.fontManager;
            drawVisitor.RendererModel = this.rendererModel;
            diagram.Accept(drawVisitor, this.transform);
        }
Пример #21
0
        /// <summary>
        /// Paint an IChemModel using the IDrawVisitor at a scale determined by the
        /// bond length in RendererModel.
        /// </summary>
        /// <param name="chemModel">the chem model to draw</param>
        /// <param name="drawVisitor">the visitor used to draw with</param>
        /// <returns>the rectangular area that the diagram will occupy on screen</returns>
        public Rect Paint(IChemModel chemModel, IDrawVisitor drawVisitor)
        {
            var moleculeSet = chemModel.MoleculeSet;
            var reactionSet = chemModel.ReactionSet;

            if (moleculeSet == null && reactionSet != null)
            {
                Rect totalBounds = BoundsCalculator.CalculateBounds(reactionSet);
                this.SetupTransformNatural(totalBounds);
                IRenderingElement diagram = reactionSetRenderer.GenerateDiagram(reactionSet);
                this.Paint(drawVisitor, diagram);
                return(this.ConvertToDiagramBounds(totalBounds));
            }

            if (moleculeSet != null && reactionSet == null)
            {
                Rect totalBounds = BoundsCalculator.CalculateBounds(moleculeSet);
                this.SetupTransformNatural(totalBounds);
                IRenderingElement diagram = moleculeSetRenderer.GenerateDiagram(moleculeSet);
                this.Paint(drawVisitor, diagram);
                return(this.ConvertToDiagramBounds(totalBounds));
            }

            if (moleculeSet != null && reactionSet != null)
            {
                var totalBounds = BoundsCalculator.CalculateBounds(chemModel);

                this.SetupTransformNatural(totalBounds);

                ElementGroup diagram = new ElementGroup
                {
                    reactionSetRenderer.GenerateDiagram(reactionSet),
                    moleculeSetRenderer.GenerateDiagram(moleculeSet)
                };

                this.Paint(drawVisitor, diagram);

                // the size of the painted diagram is returned
                return(this.ConvertToDiagramBounds(totalBounds));
            }
            return(new Rect(0, 0, 0, 0));
        }
Пример #22
0
        public virtual void TestSingleBond()
        {
            IAtomContainer container = MakeSingleBond();

            model.SetCompactAtom(true);
            model.SetCompactShape(AtomShapeType.Oval);
            model.SetShowEndCarbons(true);

            // generate the single line element
            IRenderingElement root = generator.Generate(container, model);
            var elements           = elementUtil.GetAllSimpleElements(root);

            Assert.AreEqual(2, elements.Count);

            // test that the endpoints are distinct
            OvalElement ovalA = (OvalElement)elements[0];
            OvalElement ovalB = (OvalElement)elements[1];

            Assert.AreNotSame(0, Distance(ovalA.Coord, ovalB.Coord));
        }
Пример #23
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()}");
        }
Пример #24
0
 public void Visit(IRenderingElement element)
 {
     if (element is ElementGroup)
     {
         if (getElementGroups)
         {
             this.elements.Add(element);
         }
         ((ElementGroup)element).Visit(this);
     }
     else if (element is MarkedElement)
     {
         Visit(((MarkedElement)element).Element());
     }
     else if (element is Bounds)
     {
         Visit(((Bounds)element).Root);
     }
     else
     {
         this.elements.Add(element);
     }
 }
Пример #25
0
        /// <summary>
        /// Paint a molecule (an IAtomContainer).
        /// </summary>
        /// <param name="atomContainer">the molecule 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(IAtomContainer atomContainer, IDrawVisitor drawVisitor, Rect bounds, bool resetCenter)
        {
            if (atomContainer.Bonds.Count > 0 || atomContainer.Atoms.Count == 1)
            {
                rendererModel.SetScale(
                    CalculateScaleForBondLength(GeometryUtil.GetBondLengthAverage(atomContainer)));
            }
            else if (atomContainer.Atoms.Count > 1)
            {
                rendererModel.SetScale(
                    CalculateScaleForBondLength(EstimatedBondLength(atomContainer)));
            }

            // the diagram to draw
            IRenderingElement diagram = GenerateDiagram(atomContainer);

            // the bounds of the model from 'Bounds' elements
            // no bounding elements, use the atom coordinates
            var modelBounds = GetBounds(diagram) ?? BoundsCalculator.CalculateBounds(atomContainer);

            SetupTransformToFit(bounds, modelBounds, resetCenter);

            this.Paint(drawVisitor, diagram);
        }
Пример #26
0
 public abstract void Visit(IRenderingElement element, Transform transform);
Пример #27
0
 public abstract void Visit(IRenderingElement element);
Пример #28
0
 public override void Visit(IRenderingElement element, Transform transform)
 {
 }
Пример #29
0
 /// <summary>
 /// Add the specified element bounds.
 /// </summary>
 public void Add(IRenderingElement element)
 {
     elements.Add(element);
     Traverse(element);
 }
Пример #30
0
 /// <summary>
 /// An bounding box around the specified element.
 /// </summary>
 public Bounds(IRenderingElement element)
     : this()
 {
     Add(element);
 }