/// <summary> /// Returns the geometry of a wedge bond. Hatch bonds use the same geometry /// but a different brush. /// </summary> /// <param name="desc">Descriptor defining the bond shape</param> /// <param name="perp">perpendicular vector to the bond</param> public static void GetWedgePoints(WedgeBondLayout desc, Vector perp) { desc.FirstCorner = desc.End + perp; desc.SecondCorner = desc.End - perp; desc.Boundary.AddRange(new[] { desc.Start, desc.FirstCorner, desc.SecondCorner }); }
/// <summary> /// Gets the geometry of a wedge bond. /// </summary> /// <param name="desc">WedgeBondDescriptor which is populated</param> /// <param name="standardBondLength">Standard bond length as defined by the model</param> /// <param name="standoff">Boundary width between atom label and bond terminus</param> public static void GetWedgeBondGeometry(WedgeBondLayout desc, double standardBondLength, double standoff) { //get the width of the wedge bond's thick end var bondVector = desc.PrincipleVector; var perpVector = bondVector.Perpendicular(); perpVector.Normalize(); perpVector *= standardBondLength * Globals.BondOffsetPercentage; // shrink the bond so it doesn't overlap any AtomVisuals AdjustTerminus(ref desc.Start, desc.End, desc.StartAtomHull, standoff); AdjustTerminus(ref desc.End, desc.Start, desc.EndAtomHull, standoff); //then draw it GetWedgePoints(desc, perpVector); //and pass it back as a Geometry StreamGeometry sg; sg = desc.GetOutline(); sg.Freeze(); desc.DefiningGeometry = sg; }
public static BondLayout GetBondDescriptor(AtomVisual startAtomVisual, AtomVisual endAtomVisual, double modelXamlBondLength, Globals.BondStereo parentStereo, Point startAtomPosition, Point endAtomPosition, double?parentOrderValue, Globals.BondDirection parentPlacement, Point?centroid, Point?secondaryCentroid) { if (parentStereo == Globals.BondStereo.Wedge || parentStereo == Globals.BondStereo.Hatch) { WedgeBondLayout wbd = new WedgeBondLayout() { Start = startAtomPosition, End = endAtomPosition, StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual }; var endAtom = endAtomVisual.ParentAtom; var otherBonds = endAtom.Bonds.Except(new[] { startAtomVisual.ParentAtom.BondBetween(endAtom) }).ToList(); Bond bond = null; if (otherBonds.Any()) { bond = otherBonds.ToArray()[0]; } bool chamferBond = (otherBonds.Any() && (endAtom.Element as Element) == Globals.PeriodicTable.C && endAtom.SymbolText == "" && bond.Order == Globals.OrderSingle); if (!chamferBond) { wbd.CappedOff = false; BondGeometry.GetWedgeBondGeometry(wbd, modelXamlBondLength); } else { var nonHPs = (from b in otherBonds select b.OtherAtom(endAtom).Position).ToList(); if (nonHPs.Any()) { wbd.CappedOff = true; BondGeometry.GetChamferedWedgeGeometry(wbd, modelXamlBondLength, nonHPs); } else { wbd.CappedOff = false; BondGeometry.GetWedgeBondGeometry(wbd, modelXamlBondLength); } } return(wbd); } //wavy bond if (parentStereo == Globals.BondStereo.Indeterminate && parentOrderValue == 1.0) { BondLayout sbd = new BondLayout { Start = startAtomPosition, End = endAtomPosition, StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual }; BondGeometry.GetWavyBondGeometry(sbd, modelXamlBondLength); return(sbd); } switch (parentOrderValue) { //indeterminate double case 2 when parentStereo == Globals.BondStereo.Indeterminate: DoubleBondLayout dbd = new DoubleBondLayout() { StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual, Start = startAtomPosition, End = endAtomPosition }; BondGeometry.GetCrossedDoubleGeometry(dbd, modelXamlBondLength); return(dbd); //partial or undefined bonds case 0: case 0.5: case 1.0: BondLayout sbd = new BondLayout { Start = startAtomPosition, End = endAtomPosition, StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual }; BondGeometry.GetSingleBondGeometry(sbd); return(sbd); //double bond & 1.5 bond case 1.5: case 2: DoubleBondLayout dbd2 = new DoubleBondLayout() { StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual, Start = startAtomPosition, End = endAtomPosition, Placement = parentPlacement, PrimaryCentroid = centroid, SecondaryCentroid = secondaryCentroid }; BondGeometry.GetDoubleBondGeometry(dbd2, modelXamlBondLength); return(dbd2); //triple and 2.5 bond case 2.5: case 3: TripleBondLayout tbd = new TripleBondLayout() { StartAtomVisual = startAtomVisual, EndAtomVisual = endAtomVisual, Start = startAtomPosition, End = endAtomPosition, Placement = parentPlacement, PrimaryCentroid = centroid, SecondaryCentroid = secondaryCentroid }; BondGeometry.GetTripleBondGeometry(tbd, modelXamlBondLength); return(tbd); default: return(null); } }
/// <summary> /// Chamfers or forks the end of a wedge bond under special circumstances /// (one or more incoming single bonds) /// </summary> /// <param name="descriptor"> WedgeBondDescriptor to be populated</param> /// <param name="standardBondLength">Standard bond length as defined by the model</param> /// <param name="otherAtomPoints">List of positions of atoms splaying from the end atom</param> /// <param name="standoff"></param> public static void GetChamferedWedgeGeometry(WedgeBondLayout descriptor, double standardBondLength, List <Point> otherAtomPoints, double standoff) { var bondVector = descriptor.PrincipleVector; //first get an unaltered bond GetWedgeBondGeometry(descriptor, standardBondLength, standoff); var firstEdgeVector = descriptor.FirstCorner - descriptor.Start; var secondEdgeVector = descriptor.SecondCorner - descriptor.Start; //get the two bonds with widest splay var widestPoints = from Point p in otherAtomPoints orderby Math.Abs(Vector.AngleBetween(bondVector, p - descriptor.End)) descending select p; //the scaling factors are what we multiply the bond edge vectors by double firstScalingFactor = 0d; double secondScalingFactor = 0d; //work out the biggest scaling factor for either long edge foreach (var point in widestPoints) { BasicGeometry.IntersectLines(descriptor.Start, descriptor.FirstCorner, descriptor.End, point, out var firstEdgeCut, out var otherBond1Cut); BasicGeometry.IntersectLines(descriptor.Start, descriptor.SecondCorner, descriptor.End, point, out var secondEdgeCut, out var otherBond2Cut); if (otherAtomPoints.Count == 1) { if (firstEdgeCut > firstScalingFactor) { firstScalingFactor = firstEdgeCut; } if (secondEdgeCut > secondScalingFactor) { secondScalingFactor = secondEdgeCut; } } else { if (firstEdgeCut > firstScalingFactor && otherBond1Cut < 1d && otherBond1Cut > 0d) { firstScalingFactor = firstEdgeCut; } if (secondEdgeCut > secondScalingFactor && otherBond2Cut < 1d && otherBond2Cut > 0d) { secondScalingFactor = secondEdgeCut; } } } //and multiply the edges by the scaling factors descriptor.FirstCorner = firstEdgeVector * firstScalingFactor + descriptor.Start; descriptor.SecondCorner = secondEdgeVector * secondScalingFactor + descriptor.Start; descriptor.CappedOff = true; var sg = descriptor.GetOutline(); sg.Freeze(); descriptor.DefiningGeometry = sg; }
public static BondLayout GetBondDescriptor(AtomVisual startAtomVisual, AtomVisual endAtomVisual, double modelXamlBondLength, Globals.BondStereo parentStereo, Point startAtomPosition, Point endAtomPosition, double?parentOrderValue, Globals.BondDirection parentPlacement, Point?centroid, Point?secondaryCentroid, double standoff) { List <Point> startAtomHull = new List <Point>(); List <Point> endAtomHull = new List <Point>(); if (startAtomVisual.ParentAtom.SymbolText != "" || startAtomVisual.ShowAllCarbons) { startAtomHull = startAtomVisual.Hull; } if (endAtomVisual.ParentAtom.SymbolText != "" || endAtomVisual.ShowAllCarbons) { endAtomHull = endAtomVisual.Hull; } if ((parentStereo == Globals.BondStereo.Wedge || parentStereo == Globals.BondStereo.Hatch) && parentOrderValue == 1) { WedgeBondLayout wbd = new WedgeBondLayout { Start = startAtomPosition, End = endAtomPosition, StartAtomHull = startAtomHull, EndAtomHull = endAtomHull }; var endAtom = endAtomVisual.ParentAtom; var otherBonds = endAtom.Bonds.Except(new[] { startAtomVisual.ParentAtom.BondBetween(endAtom) }).ToList(); Bond bond = null; bool oblique = true; if (otherBonds.Any()) { bond = otherBonds.ToArray()[0]; Vector wedgevector = wbd.End - wbd.Start; foreach (Bond b in otherBonds) { Atom otherAtom = b.OtherAtom(endAtom); Vector v = wbd.End - otherAtom.Position; double angle = System.Math.Abs(Vector.AngleBetween(wedgevector, v)); if (angle < 109.5 || angle > 130.5) { oblique = false; break; } } } bool chamferBond = otherBonds.Any() && oblique && (endAtom.Element as Element) == Globals.PeriodicTable.C && endAtom.SymbolText == "" && bond.Order == Globals.OrderSingle; if (!chamferBond) { wbd.CappedOff = false; BondGeometry.GetWedgeBondGeometry(wbd, modelXamlBondLength, standoff); } else { var nonHPs = (from b in otherBonds select b.OtherAtom(endAtom).Position).ToList(); if (nonHPs.Any()) { wbd.CappedOff = true; BondGeometry.GetChamferedWedgeGeometry(wbd, modelXamlBondLength, nonHPs, standoff); } else { wbd.CappedOff = false; BondGeometry.GetWedgeBondGeometry(wbd, modelXamlBondLength, standoff); } } return(wbd); } //wavy bond if (parentStereo == Globals.BondStereo.Indeterminate && parentOrderValue == 1.0) { BondLayout sbd = new BondLayout { Start = startAtomPosition, End = endAtomPosition, StartAtomHull = startAtomHull, EndAtomHull = endAtomHull }; BondGeometry.GetWavyBondGeometry(sbd, modelXamlBondLength, standoff); return(sbd); } switch (parentOrderValue) { //indeterminate double case 2 when parentStereo == Globals.BondStereo.Indeterminate: DoubleBondLayout dbd = new DoubleBondLayout() { StartAtomHull = startAtomHull, EndAtomHull = endAtomHull, Start = startAtomPosition, End = endAtomPosition, StartNeigbourPositions = (from Atom a in startAtomVisual.ParentAtom.NeighboursExcept(endAtomVisual.ParentAtom) select a.Position).ToList(), EndNeighbourPositions = (from Atom a in endAtomVisual.ParentAtom.NeighboursExcept(startAtomVisual.ParentAtom) select a.Position).ToList() }; BondGeometry.GetCrossedDoubleGeometry(dbd, modelXamlBondLength, standoff); return(dbd); //partial or undefined bonds case 0: case 0.5: case 1.0: BondLayout sbd = new BondLayout { Start = startAtomPosition, End = endAtomPosition, StartAtomHull = startAtomHull, EndAtomHull = endAtomHull }; BondGeometry.GetSingleBondGeometry(sbd, standoff); return(sbd); //double bond & 1.5 bond case 1.5: case 2: DoubleBondLayout dbd2 = new DoubleBondLayout() { StartAtomHull = startAtomHull, EndAtomHull = endAtomHull, Start = startAtomPosition, End = endAtomPosition, Placement = parentPlacement, PrimaryCentroid = centroid, SecondaryCentroid = secondaryCentroid, StartNeigbourPositions = (from Atom a in startAtomVisual.ParentAtom.NeighboursExcept(endAtomVisual.ParentAtom) select a.Position).ToList(), EndNeighbourPositions = (from Atom a in endAtomVisual.ParentAtom.NeighboursExcept(startAtomVisual.ParentAtom) select a.Position).ToList() }; BondGeometry.GetDoubleBondGeometry(dbd2, modelXamlBondLength, standoff); return(dbd2); //triple and 2.5 bond case 2.5: case 3: TripleBondLayout tbd = new TripleBondLayout() { StartAtomHull = startAtomHull, EndAtomHull = endAtomHull, Start = startAtomPosition, End = endAtomPosition, Placement = parentPlacement, PrimaryCentroid = centroid, SecondaryCentroid = secondaryCentroid }; BondGeometry.GetTripleBondGeometry(tbd, modelXamlBondLength, standoff); return(tbd); default: return(null); } }