/// <summary> /// Reads the atom type mappings from the data file. /// </summary> /// <returns>a <see cref="IReadOnlyDictionary{TKey, TValue}"/> with atom type mappings. <see langword="null"/>, if some reading error occurred.</returns> public IReadOnlyDictionary <string, string> ReadAtomTypeMappings() { IReadOnlyDictionary <string, string> mappings = null; var setting = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse, ValidationFlags = XmlSchemaValidationFlags.None }; var handler = new OWLAtomTypeMappingHandler(); var parser = XmlReader.Create(input, setting); var reader = new XReader { Handler = handler }; try { var doc = XDocument.Load(parser); reader.Read(doc); mappings = handler.GetAtomTypeMappings(); } catch (IOException exception) { Trace.TraceError(nameof(IOException) + ": " + exception.Message); Debug.WriteLine(exception); } catch (XmlException saxe) { Trace.TraceError(nameof(XmlException) + ": " + saxe.Message); Debug.WriteLine(saxe); } return(mappings ?? Dictionaries.Empty <string, string>()); }
public bool ContainsPrimaryKeyValue(TPrimaryKey primaryKey, TValue value) { var secondaryEntry = dictionary.ContainsKey(primaryKey) ? dictionary[primaryKey] : Dictionaries.Empty <TSecondaryKey, TValue>(); return(secondaryEntry.Any(entry => Objects.Equal(entry.Value, value))); }
public ICollection <KeyValuePair <TSecondaryKey, TValue> > PrimaryKeyEntries(TPrimaryKey primaryKey) { var secondaryDictionary = dictionary.ContainsKey(primaryKey) ? dictionary[primaryKey] : Dictionaries.Empty <TSecondaryKey, TValue>(); return(secondaryDictionary.Entries()); }
public void ShouldCreateEmptyDictionary() { // when var dictionary = Dictionaries.Empty <string, int>(); // then Check.That(dictionary).IsEmpty(); }
public ICollection <TValue> RemoveByPrimaryKey(TPrimaryKey primaryKey) { var removed = dictionary.ContainsKey(primaryKey) ? dictionary[primaryKey] : Dictionaries.Empty <TSecondaryKey, TValue>(); dictionary.Remove(primaryKey); RecalculateSize(); return(removed.Values); }
public void ShouldReturnNullObjectIfNotPresentInDictionary() { // given var dictionary = Dictionaries.Empty <string, string>(); // when var value = dictionary.GetIfPresent("not exising"); // then Check.That(value).IsNull(); }
private IRenderingElement GenerateMultipleSgroup(Sgroup sgroup) { // just draw the brackets - multiplied group parts have already been hidden in prep phase var brackets = (IList <SgroupBracket>)sgroup.GetValue(SgroupKey.CtabBracket); if (brackets != null) { return(GenerateSgroupBrackets(sgroup, brackets, Dictionaries.Empty <IAtom, AtomSymbol>(), (string)sgroup.GetValue(SgroupKey.CtabSubScript), null)); } else { return(new ElementGroup()); } }
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); }
/// <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)); }
/// <summary> /// Depict a set of molecules, they will be depicted in a grid with the /// specified number of rows and columns. Rows are filled first and then /// columns. /// </summary> /// <param name="mols">molecules</param> /// <param name="nrow">number of rows</param> /// <param name="ncol">number of columns</param> /// <returns>depiction</returns> /// <exception cref="CDKException">a depiction could not be generated</exception> public Depiction Depict(IEnumerable <IAtomContainer> mols, int nrow, int ncol, IReadOnlyDictionary <IChemObject, Color> highlight = null) { if (highlight == null) { highlight = Dictionaries.Empty <IChemObject, Color>(); } var layoutBackups = new List <LayoutBackup>(); int molId = 0; foreach (var mol in mols) { SetIfMissing(mol, MarkedElement.IdKey, "mol" + ++molId); layoutBackups.Add(new LayoutBackup(mol)); } // ensure we have coordinates, generate them if not // we also rescale the molecules such that all bond // lengths are the same. PrepareCoords(mols); // highlight parts foreach (var e in highlight) { e.Key.SetProperty(StandardGenerator.HighlightColorKey, e.Value); } // generate bound rendering elements var model = CreateModel(); // setup the model scale var molList = mols.ToList(); model.SetScale(CaclModelScale(molList)); var molElems = Generate(molList, model, 1); // reset molecule coordinates foreach (LayoutBackup backup in layoutBackups) { backup.Reset(); } // generate titles (if enabled) var titles = new List <Bounds>(); if (model.GetShowMoleculeTitle()) { foreach (var mol in mols) { titles.Add(GenerateTitle(model, mol, model.GetScale())); } } // remove current highlight buffer foreach (var obj in highlight.Keys) { obj.RemoveProperty(StandardGenerator.HighlightColorKey); } return(new MolGridDepiction(model, molElems, titles, dimensions, nrow, ncol)); }