/// <summary> /// Returns the drawing color of the given atom. An atom is colored as /// highlighted if highlighted. The atom is color marked if in a /// substructure. If not, the color from the CDK2DAtomColor is used (if /// selected). Otherwise, the atom is colored black. /// </summary> protected internal virtual Color GetAtomColor(IAtom atom, RendererModel model) { var atomColor = model.GetAtomColor(); if (model.GetAtomColorByType()) { atomColor = model.GetAtomColorer().GetAtomColor(atom); } return(atomColor); }
/// <summary> /// Create a new generator for a molecule. /// </summary> /// <param name="mol">molecule</param> /// <param name="font">the font</param> /// <param name="emSize">the font size</param> /// <param name="model">the rendering parameters</param> public StandardDonutGenerator(IAtomContainer mol, Typeface font, double emSize, RendererModel model, double stroke) { this.mol = mol; this.font = font; this.emSize = emSize; this.forceDelocalised = model.GetForceDelocalisedBondDisplay(); this.delocalisedDonuts = model.GetDelocalisedDonutsBondDisplay(); this.dbSpacing = model.GetBondSeparation(); this.scale = model.GetScale(); this.stroke = stroke; this.fgColor = model.GetAtomColorer().GetAtomColor(CDK.Builder.NewAtom("C")); }
/// <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)); }
/// <summary> /// Depict a reaction. /// </summary> /// <param name="rxn">reaction instance</param> /// <returns>depiction</returns> /// <exception cref="CDKException">a depiction could not be generated</exception> public Depiction Depict(IReaction rxn, IReadOnlyDictionary <IChemObject, Color> highlight = null) { if (highlight == null) { highlight = Dictionaries.Empty <IChemObject, Color>(); } Ensure2DLayout(rxn); // can reorder components! var fgcol = templateModel.GetAtomColorer().GetAtomColor(rxn.Builder.NewAtom("C")); var reactants = rxn.Reactants.ToList(); var products = rxn.Products.ToList(); var agents = rxn.Agents.ToList(); List <LayoutBackup> layoutBackups = new List <LayoutBackup>(); // set ids for tagging elements int molId = 0; foreach (var mol in reactants) { SetIfMissing(mol, MarkedElement.IdKey, "mol" + ++molId); SetIfMissing(mol, MarkedElement.ClassKey, "reactant"); layoutBackups.Add(new LayoutBackup(mol)); } foreach (var mol in products) { SetIfMissing(mol, MarkedElement.IdKey, "mol" + ++molId); SetIfMissing(mol, MarkedElement.ClassKey, "product"); layoutBackups.Add(new LayoutBackup(mol)); } foreach (var mol in agents) { SetIfMissing(mol, MarkedElement.IdKey, "mol" + ++molId); SetIfMissing(mol, MarkedElement.ClassKey, "agent"); layoutBackups.Add(new LayoutBackup(mol)); } var myHighlight = new Dictionary <IChemObject, Color>(); if (atomMapColors != null) { foreach (var e in MakeHighlightAtomMap(reactants, products)) { myHighlight[e.Key] = e.Value; } } // user highlight buffer pushes out the atom-map highlight if provided foreach (var e in highlight) { myHighlight[e.Key] = e.Value; } PrepareCoords(reactants); PrepareCoords(products); PrepareCoords(agents); // highlight parts foreach (var e in myHighlight) { e.Key.SetProperty(StandardGenerator.HighlightColorKey, e.Value); } // setup the model scale based on bond length var scale = this.CaclModelScale(rxn); var model = CreateModel(); model.SetScale(scale); // reactant/product/agent element generation, we number the reactants, then products then agents var reactantBounds = Generate(reactants, model, 1); var productBounds = Generate(rxn.Products.ToList(), model, rxn.Reactants.Count); var agentBounds = Generate(rxn.Agents.ToList(), model, rxn.Reactants.Count + rxn.Products.Count); // remove current highlight buffer foreach (var obj in myHighlight.Keys) { obj.RemoveProperty(StandardGenerator.HighlightColorKey); } // generate a 'plus' element var plus = GeneratePlusSymbol(scale, fgcol); // reset the coordinates to how they were before we invoked depict foreach (LayoutBackup backup in layoutBackups) { backup.Reset(); } var emptyBounds = new Bounds(); var title = model.GetShowReactionTitle() ? GenerateTitle(model, rxn, scale) : emptyBounds; var reactantTitles = new List <Bounds>(); var productTitles = new List <Bounds>(); if (model.GetShowMoleculeTitle()) { foreach (IAtomContainer reactant in reactants) { reactantTitles.Add(GenerateTitle(model, reactant, scale)); } foreach (IAtomContainer product in products) { productTitles.Add(GenerateTitle(model, product, scale)); } } Bounds conditions = GenerateReactionConditions(rxn, fgcol, model.GetScale()); return(new ReactionDepiction(model, reactantBounds, productBounds, agentBounds, plus, rxn.Direction, dimensions, reactantTitles, productTitles, title, conditions, fgcol)); }