Beispiel #1
0
        /// <summary>
        ///     draws the two parallel lines of a double bond
        ///     These bonds can either straddle the atom-atom line or fall to one or other side of it
        /// </summary>
        /// <param name="descriptor">DoubleBondDescriptor which is populated</param>
        /// <param name="standardBondLength">Standard bond length as defined by the model</param>
        /// <param name="standoff"></param>
        /// <returns></returns>
        public static void GetDoubleBondGeometry(DoubleBondLayout descriptor, double standardBondLength, double standoff)

        {
            //get the standard points for a double bond
            GetDoubleBondPoints(descriptor, standardBondLength);
            //adjust the line ends
            if (descriptor.StartAtomHull != null)
            {
                AdjustTerminus(ref descriptor.Start, descriptor.End, descriptor.StartAtomHull, standoff);
                AdjustTerminus(ref descriptor.SecondaryStart, descriptor.SecondaryEnd, descriptor.StartAtomHull, standoff);
            }

            if (descriptor.EndAtomHull != null)
            {
                AdjustTerminus(ref descriptor.End, descriptor.Start, descriptor.EndAtomHull, standoff);
                AdjustTerminus(ref descriptor.SecondaryEnd, descriptor.SecondaryStart, descriptor.EndAtomHull, standoff);
            }
            //and draw it
            var sg = new StreamGeometry();

            using (var sgc = sg.Open())
            {
                sgc.BeginFigure(descriptor.Start, false, false);
                sgc.LineTo(descriptor.End, true, false);
                sgc.BeginFigure(descriptor.SecondaryStart, false, false);
                sgc.LineTo(descriptor.SecondaryEnd, true, false);
                sgc.Close();
            }

            sg.Freeze();
            descriptor.DefiningGeometry = sg;
        }
Beispiel #2
0
        /// <summary>
        ///     Defines a double bond
        /// </summary>
        /// <param name="descriptor">DoubleBondDescriptor which is populated</param>
        /// <param name="standardBondLength">Standard bond length as defined by the model</param>
        /// <returns></returns>
        public static void GetDoubleBondPoints(DoubleBondLayout descriptor, double standardBondLength)
        {
            Point?point3a;
            Point?point4a;

            //use a struct here to return the values
            GetDefaultDoubleBondPoints(descriptor, standardBondLength);

            if (descriptor.PrimaryCentroid != null)
            //now, if there is a centroid defined, the bond is part of a ring
            {
                Point?workingCentroid = null;
                //work out whether the bond is place inside or outside the ring
                var bondvector   = descriptor.PrincipleVector;
                var centreVector = descriptor.PrimaryCentroid - descriptor.Start;

                var computedPlacement = (BondDirection)Math.Sign(Vector.CrossProduct(centreVector.Value, bondvector));

                if (descriptor.Placement != BondDirection.None)
                {
                    if (computedPlacement == descriptor.Placement) //then we have nothing to worry about
                    {
                        workingCentroid = descriptor.PrimaryCentroid;
                    }
                    else //we need to adjust the points according to the other centroid
                    {
                        workingCentroid = descriptor.SecondaryCentroid;
                    }
                }

                if (workingCentroid != null)

                {
                    //shorten the secondto fit neatly within the ring
                    point3a = BasicGeometry.LineSegmentsIntersect(descriptor.Start, workingCentroid.Value,
                                                                  descriptor.SecondaryStart,
                                                                  descriptor.SecondaryEnd);
                    point4a = BasicGeometry.LineSegmentsIntersect(descriptor.End, workingCentroid.Value,
                                                                  descriptor.SecondaryStart,
                                                                  descriptor.SecondaryEnd);
                    var tempPoint3 = point3a ?? descriptor.SecondaryStart;
                    var tempPoint4 = descriptor.SecondaryEnd = point4a ?? descriptor.SecondaryEnd;

                    descriptor.SecondaryStart = tempPoint3;
                    descriptor.SecondaryEnd   = tempPoint4;
                }
                //get the boundary for hit testing purposes
                descriptor.Boundary.Clear();
                descriptor.Boundary.AddRange(new[]
                {
                    descriptor.Start, descriptor.End, descriptor.SecondaryEnd,
                    descriptor.SecondaryStart
                });
            }
        }
Beispiel #3
0
        /// <summary>
        /// Gets an unadjusted set of points for a double bond
        /// </summary>
        /// <param name="descriptor">DoubleBondDescriptor which is populated</param>
        /// <param name="standardBondLength">Standard bond length as defined by the model</param>
        private static void GetDefaultDoubleBondPoints(DoubleBondLayout descriptor, double standardBondLength)
        {
            var v      = descriptor.PrincipleVector;
            var normal = v.Perpendicular();

            normal.Normalize();

            var distance = standardBondLength * BondOffsetPercentage;
            //first, calculate the default bond points as if there were no rings involved
            var tempStart = descriptor.Start;

            //offset according to placement
            switch (descriptor.Placement)
            {
            case BondDirection.None:

                descriptor.Start = tempStart + normal * distance;
                descriptor.End   = descriptor.Start + v;

                descriptor.SecondaryStart = tempStart - normal * distance;
                descriptor.SecondaryEnd   = descriptor.SecondaryStart + v;

                break;

            case BondDirection.Clockwise:
            {
                descriptor.SecondaryStart = tempStart - normal * 2 * distance;
                descriptor.SecondaryEnd   = descriptor.SecondaryStart + v;

                break;
            }

            case BondDirection.Anticlockwise:

                descriptor.SecondaryStart = tempStart + normal * 2 * distance;
                descriptor.SecondaryEnd   = descriptor.SecondaryStart + v;
                break;

            default:

                descriptor.Start = tempStart + normal * distance;
                descriptor.End   = descriptor.Start + v;

                descriptor.SecondaryStart = tempStart - normal * distance;
                descriptor.SecondaryEnd   = descriptor.SecondaryStart + v;
                break;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Draws the crossed double bond to indicate indeterminate geometry
        /// </summary>
        /// <param name="descriptor">BondLayout to hadle the physical bond shape</param>
        /// <param name="standardBondLength">Model's standard bond length</param>
        /// <param name="standoff">Boundary width between atom label and bond terminus</param>
        public static void GetCrossedDoubleGeometry(DoubleBondLayout descriptor, double standardBondLength, double standoff)
        {
            var v      = descriptor.PrincipleVector;
            var normal = v.Perpendicular();

            normal.Normalize();

            Point point1, point2, point3, point4;

            var distance = standardBondLength * Globals.BondOffsetPercentage;

            point1 = descriptor.Start + normal * distance;
            point2 = point1 + v;

            point3 = descriptor.Start - normal * distance;
            point4 = point3 + v;

            if (descriptor.StartAtomHull != null)
            {
                AdjustTerminus(ref point1, point2, descriptor.StartAtomHull, standoff);
                AdjustTerminus(ref point3, point4, descriptor.StartAtomHull, standoff);
            }

            if (descriptor.StartAtomHull != null)
            {
                AdjustTerminus(ref point2, point1, descriptor.StartAtomHull, standoff);
                AdjustTerminus(ref point4, point3, descriptor.StartAtomHull, standoff);
            }

            var sg = new StreamGeometry();

            using (var sgc = sg.Open())
            {
                sgc.BeginFigure(point1, false, false);
                sgc.LineTo(point4, true, false);
                sgc.BeginFigure(point2, false, false);
                sgc.LineTo(point3, true, false);
                sgc.Close();
            }

            sg.Freeze();
            descriptor.DefiningGeometry = sg;
            descriptor.Boundary.Clear();
            descriptor.Boundary.AddRange(new[] { point1, point2, point4, point3 });
        }
Beispiel #5
0
        /// <summary>
        /// Renders a bond to the display
        /// </summary>
        public override void Render()
        {
            //set up the shared variables first
            Point startPoint, endPoint;

            startPoint = ParentBond.StartAtom.Position;
            endPoint   = ParentBond.EndAtom.Position;

            var bondLength = ParentBond.Model.XamlBondLength;
            var cv1        = ChemicalVisuals.ContainsKey(ParentBond.StartAtom);
            var cv2        = ChemicalVisuals.ContainsKey(ParentBond.EndAtom);

            //bale out in case we have a null start or end
            if (!cv1 || !cv2)
            {
                // Abort if either ChemicalVisual is missing !
                return;
            }

            //now get the geometry of start and end atoms
            var startVisual = (AtomVisual)ChemicalVisuals[ParentBond.StartAtom];

            var endVisual = (AtomVisual)ChemicalVisuals[ParentBond.EndAtom];

            //first grab the main descriptor
            BondDescriptor = GetBondDescriptor(ParentBond, startVisual, endVisual, bondLength);

            _enclosingPoly = BondDescriptor.Boundary;
            //set up the default pens for rendering
            _mainBondPen = new Pen(Brushes.Black, BondThickness)
            {
                StartLineCap = PenLineCap.Round,
                EndLineCap   = PenLineCap.Round,
                LineJoin     = PenLineJoin.Miter
            };

            _subsidiaryBondPen = _mainBondPen.Clone();

            switch (ParentBond.Order)
            {
            case Globals.OrderZero:
            case Globals.OrderOther:
            case "unknown":
                // Handle Zero Bond
                _mainBondPen.DashStyle = DashStyles.Dot;

                using (DrawingContext dc = RenderOpen())
                {
                    dc.DrawGeometry(Brushes.Black, _mainBondPen, BondDescriptor.DefiningGeometry);
                    //we need to draw another transparent rectangle to expand the bounding box
                    DrawHitTestOverlay(dc);
                    dc.Close();
                }
                DoubleBondLayout dbd = new DoubleBondLayout
                {
                    Start     = startPoint,
                    End       = endPoint,
                    Placement = ParentBond.Placement
                };

                BondGeometry.GetDoubleBondPoints(dbd, bondLength);
                _enclosingPoly = dbd.Boundary;
                break;

            case Globals.OrderPartial01:
                _mainBondPen.DashStyle = DashStyles.Dash;

                using (DrawingContext dc = RenderOpen())
                {
                    dc.DrawGeometry(Brushes.Black, _mainBondPen, BondDescriptor.DefiningGeometry);
                    //we need to draw another transparent thicker line on top of the existing one
                    DrawHitTestOverlay(dc);
                    dc.Close();
                }

                //grab the enclosing polygon as for a double ParentBond - this overcomes a hit testing bug
                DoubleBondLayout dbd2 = new DoubleBondLayout
                {
                    Start     = startPoint,
                    End       = endPoint,
                    Placement = ParentBond.Placement
                };

                BondGeometry.GetDoubleBondPoints(dbd2, bondLength);
                _enclosingPoly = dbd2.Boundary;

                break;

            case "1":
            case Globals.OrderSingle:
                // Handle Single bond
                switch (ParentBond.Stereo)
                {
                case Globals.BondStereo.Indeterminate:
                case Globals.BondStereo.None:
                case Globals.BondStereo.Wedge:
                    using (DrawingContext dc = RenderOpen())
                    {
                        dc.DrawGeometry(Brushes.Black, _mainBondPen, BondDescriptor.DefiningGeometry);
                        //we need to draw another transparent rectangle to expand the bounding box
                        DrawHitTestOverlay(dc);
                        dc.Close();
                    }
                    break;

                case Globals.BondStereo.Hatch:
                    using (DrawingContext dc = RenderOpen())
                    {
                        dc.DrawGeometry(GetHatchBrush(ParentBond.Angle), _mainBondPen, BondDescriptor.DefiningGeometry);
                        //we need to draw another transparent rectangle to expand the bounding box
                        DrawHitTestOverlay(dc);
                        dc.Close();
                    }
                    break;
                }
                break;

            case Globals.OrderPartial12:
            case Globals.OrderAromatic:
            case "2":
            case Globals.OrderDouble:
                DoubleBondLayout dbd3     = (DoubleBondLayout)BondDescriptor;
                Point?           centroid = ParentBond.Centroid;
                dbd3.PrimaryCentroid = centroid;

                if (ParentBond.Order == Globals.OrderPartial12 || ParentBond.Order == Globals.OrderAromatic)     // Handle 1.5 bond
                {
                    _subsidiaryBondPen.DashStyle = DashStyles.Dash;
                }

                _enclosingPoly = dbd3.Boundary;

                if (ParentBond.Stereo != Globals.BondStereo.Indeterminate)
                {
                    using (DrawingContext dc = RenderOpen())
                    {
                        dc.DrawLine(_mainBondPen, BondDescriptor.Start, BondDescriptor.End);
                        dc.DrawLine(_subsidiaryBondPen,
                                    dbd3.SecondaryStart,
                                    dbd3.SecondaryEnd);
                        dc.Close();
                    }
                }
                else
                {
                    using (DrawingContext dc = RenderOpen())
                    {
                        dc.DrawGeometry(_mainBondPen.Brush, _mainBondPen, BondDescriptor.DefiningGeometry);

                        dc.Close();
                    }
                }
                break;

            case Globals.OrderPartial23:
            case "3":
            case Globals.OrderTriple:
                if (ParentBond.Order == Globals.OrderPartial23)     // Handle 2.5 bond
                {
                    _subsidiaryBondPen.DashStyle = DashStyles.Dash;
                }

                var tbd = (BondDescriptor as TripleBondLayout);
                using (DrawingContext dc = RenderOpen())
                {
                    if (ParentBond.Placement == Globals.BondDirection.Clockwise)
                    {
                        dc.DrawLine(_mainBondPen, tbd.SecondaryStart, tbd.SecondaryEnd);
                        dc.DrawLine(_mainBondPen, tbd.Start, tbd.End);
                        dc.DrawLine(_subsidiaryBondPen, tbd.TertiaryStart, tbd.TertiaryEnd);
                    }
                    else
                    {
                        dc.DrawLine(_subsidiaryBondPen, tbd.SecondaryStart, tbd.SecondaryEnd);
                        dc.DrawLine(_mainBondPen, tbd.Start, tbd.End);
                        dc.DrawLine(_mainBondPen, tbd.TertiaryStart, tbd.TertiaryEnd);
                    }

                    dc.Close();
                }
                break;
            }

            void DrawHitTestOverlay(DrawingContext dc)
            {
                SolidColorBrush outliner = new SolidColorBrush(Colors.Salmon);

#if SHOWBOUNDS
                outliner.Opacity = 0.2d;
#else
                outliner.Opacity = 0d;
#endif

                Pen outlinePen = new Pen(outliner, BondThickness * 5);
                dc.DrawGeometry(outliner, outlinePen, BondDescriptor.DefiningGeometry);
            }
        }
Beispiel #6
0
        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);
            }
        }
Beispiel #7
0
        /// <summary>
        ///     Defines a double bond
        /// </summary>
        /// <param name="descriptor">DoubleBondDescriptor which is populated</param>
        /// <param name="standardBondLength">Standard bond length as defined by the model</param>
        /// <returns></returns>
        public static void GetDoubleBondPoints(DoubleBondLayout descriptor, double standardBondLength)
        {
            Point?descriptorSecondaryStart;
            Point?descriptorSecondaryEnd;

            //use a struct here to return the values
            GetDefaultDoubleBondPoints(descriptor, standardBondLength);

            if (descriptor.PrimaryCentroid != null)
            {
                //now, if there is a centroid defined, the bond is part of a ring
                Point?workingCentroid = null;
                //work out whether the bond is place inside or outside the ring
                var bondvector   = descriptor.PrincipleVector;
                var centreVector = descriptor.PrimaryCentroid - descriptor.Start;

                var computedPlacement = (Globals.BondDirection)Math.Sign(Vector.CrossProduct(centreVector.Value, bondvector));

                if (descriptor.Placement != Globals.BondDirection.None)
                {
                    if (computedPlacement == descriptor.Placement) //then we have nothing to worry about
                    {
                        workingCentroid = descriptor.PrimaryCentroid;
                    }
                    else //we need to adjust the points according to the other centroid
                    {
                        workingCentroid = descriptor.SecondaryCentroid;
                    }
                }

                if (workingCentroid != null)
                {
                    var bondVector = (descriptor.End - descriptor.Start);
                    var midPoint   = bondVector / 2 + descriptor.Start;

                    var perpAngle = Math.Abs(Vector.AngleBetween(workingCentroid.Value - midPoint, bondVector));

                    if (perpAngle >= 80 && perpAngle <= 100) //probably convex ring
                    {
                        //shorten the second bond to fit neatly within the ring
                        descriptorSecondaryStart = BasicGeometry.LineSegmentsIntersect(descriptor.Start, workingCentroid.Value,
                                                                                       descriptor.SecondaryStart,
                                                                                       descriptor.SecondaryEnd);
                        descriptorSecondaryEnd = BasicGeometry.LineSegmentsIntersect(descriptor.End, workingCentroid.Value,
                                                                                     descriptor.SecondaryStart,
                                                                                     descriptor.SecondaryEnd);
                        var tempPoint3 = descriptorSecondaryStart ?? descriptor.SecondaryStart;
                        var tempPoint4 = descriptorSecondaryEnd ?? descriptor.SecondaryEnd;

                        descriptor.SecondaryStart = tempPoint3;
                        descriptor.SecondaryEnd   = tempPoint4;
                    }
                    else //probably concave ring, so shorten by half the bond offset value
                    {
                        if (descriptor.StartNeigbourPositions != null && descriptor.EndNeighbourPositions != null)
                        {
                            SplitBondAngles(ref descriptor.SecondaryStart, descriptor.SecondaryEnd,
                                            descriptor.StartNeigbourPositions, descriptor.Start);
                            SplitBondAngles(ref descriptor.SecondaryEnd, descriptor.SecondaryStart,
                                            descriptor.EndNeighbourPositions, descriptor.End);
                        }
                    }
                }
                else //no centroid so split the angles anyway
                {
                    if (descriptor.StartNeigbourPositions != null && descriptor.EndNeighbourPositions != null)
                    {
                        SplitBondAngles(ref descriptor.SecondaryStart, descriptor.SecondaryEnd,
                                        descriptor.StartNeigbourPositions, descriptor.Start);
                        SplitBondAngles(ref descriptor.SecondaryEnd, descriptor.SecondaryStart,
                                        descriptor.EndNeighbourPositions, descriptor.End);
                    }
                }

                //get the boundary for hit testing purposes
                descriptor.Boundary.Clear();
                descriptor.Boundary.AddRange(new[]
                {
                    descriptor.Start, descriptor.End, descriptor.SecondaryEnd,
                    descriptor.SecondaryStart
                });
            }
        }
Beispiel #8
0
        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);
            }
        }