public void useDefaultPlacementWithNoBonds() { var mock_atom = new Mock <IAtom>(); var atom = mock_atom.Object; mock_atom.Setup(n => n.AtomicNumber).Returns(8); Assert.AreEqual(Left, HydrogenPositionTools.Position(atom, Array.Empty <IAtom>())); }
public void HydrogensAppearBeforeSulfur() { var mock_atom = new Mock <IAtom>(); var atom = mock_atom.Object; mock_atom.Setup(n => n.AtomicNumber).Returns(16); Assert.AreEqual(Left, HydrogenPositionTools.UsingDefaultPlacement(atom)); }
public void HydrogensAppearAfterCarbon() { var mock_atom = new Mock <IAtom>(); var atom = mock_atom.Object; mock_atom.Setup(n => n.AtomicNumber).Returns(6); Assert.AreEqual(Right, HydrogenPositionTools.UsingDefaultPlacement(atom)); }
public void HydrogensAppearBeforeWhenBondIsFromRight() { var mock_atom1 = new Mock <IAtom>(); var atom1 = mock_atom1.Object; var mock_atom2 = new Mock <IAtom>(); var atom2 = mock_atom2.Object; mock_atom1.Setup(n => n.Point2D).Returns(new Vector2(0, 0)); mock_atom2.Setup(n => n.Point2D).Returns(new Vector2(1, 0)); Assert.AreEqual(Left, HydrogenPositionTools.Position(atom1, new[] { atom2 })); }
public void Symmetric() { // all extents are the same so 'Right' is chosen in preference var vectors = new[] { new Vector2(1, 1), new Vector2(1, -1), new Vector2(-1, 1), new Vector2(-1, -1) }; Assert.AreEqual(Right, HydrogenPositionTools.UsingAngularExtent(vectors)); }
public void UsingCardinalDirection() { var mock_atom1 = new Mock <IAtom>(); var atom1 = mock_atom1.Object; var mock_atom2 = new Mock <IAtom>(); var atom2 = mock_atom2.Object; var mock_atom3 = new Mock <IAtom>(); var atom3 = mock_atom2.Object; mock_atom1.Setup(n => n.Point2D).Returns(new Vector2(0, 0)); mock_atom2.Setup(n => n.Point2D).Returns(new Vector2(1, 1)); mock_atom3.Setup(n => n.Point2D).Returns(new Vector2(1, -1)); Assert.AreEqual(Left, HydrogenPositionTools.Position(atom1, new[] { atom2, atom3 })); }
public void AngularExtentLeft() { double theta = Vectors.DegreeToRadian(120); var vectors = new[] { new Vector2(1, 0), new Vector2(Math.Cos(theta), Math.Sin(theta)), new Vector2(Math.Cos(-theta), Math.Sin(-theta)), }; Assert.AreEqual(Left, HydrogenPositionTools.UsingAngularExtent(vectors)); }
public void LargestExtent() { // the largest extents here are above and below var vectors = new[] { new Vector2(Math.Cos(Vectors.DegreeToRadian(30)), Math.Sin(Vectors.DegreeToRadian(30))), new Vector2(Math.Cos(Vectors.DegreeToRadian(-30)), Math.Sin(Vectors.DegreeToRadian(-30))), new Vector2(Math.Cos(Vectors.DegreeToRadian(150)), Math.Sin(Vectors.DegreeToRadian(150))), new Vector2(Math.Cos(Vectors.DegreeToRadian(-150)), Math.Sin(Vectors.DegreeToRadian(-150))) }; Assert.AreEqual(Above, HydrogenPositionTools.UsingAngularExtent(vectors)); }
public void AngularExtentAbove() { double theta1 = Vectors.DegreeToRadian(30); double theta2 = Vectors.DegreeToRadian(150); var vectors = new[] { new Vector2(0, -1), new Vector2(Math.Cos(theta1), Math.Sin(theta1)), new Vector2(Math.Cos(theta2), Math.Sin(theta2)), }; Assert.AreEqual(Above, HydrogenPositionTools.UsingAngularExtent(vectors)); }
public void CardinalDirectionForNorthWestIsRight() { Assert.AreEqual(Right, HydrogenPositionTools.UsingCardinalDirection(new Vector2(-1, 0))); }
public void CardinalDirectionForSouthIsAbove() { Assert.AreEqual(Above, HydrogenPositionTools.UsingCardinalDirection(new Vector2(0, -1))); }
public void CardinalDirectionForSouthEastIsLeft() { Assert.AreEqual(Left, HydrogenPositionTools.UsingCardinalDirection(new Vector2(1, -1))); }
public void CardinalDirectionForNorthIsBelow() { Assert.AreEqual(Below, HydrogenPositionTools.UsingCardinalDirection(new Vector2(0, 1))); }
public void ValueOf() { Assert.AreEqual(HydrogenPosition.Above, HydrogenPositionTools.Parse("Above")); }
/// <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); }