Beispiel #1
0
        /// <summary>
        /// Generated coordinates for a given ring, which is fused to another ring.
        /// The rings share exactly one bond.
        /// </summary>
        /// <param name="ring">The ring to be placed</param>
        /// <param name="sharedAtoms">The atoms of this ring, also members of another ring, which are already placed</param>
        /// <param name="ringCenterVector">A vector pointing the the center of the new ring</param>
        /// <param name="bondLength">The standard bondlength</param>
        public virtual void PlaceFusedRing(IRing ring,
                                           IAtomContainer sharedAtoms,
                                           Vector2 ringCenterVector,
                                           double bondLength)
        {
            Debug.WriteLine("RingPlacer.PlaceFusedRing() start");

            IAtom beg = sharedAtoms.Atoms[0];
            IAtom end = sharedAtoms.Atoms[1];

            Vector2 pBeg = beg.Point2D.Value;
            Vector2 pEnd = end.Point2D.Value;

            // fuse the ring perpendicular to the bond, ring center is not
            // sub-optimal if non-regular/convex polygon (e.g. macro cycle)
            ringCenterVector = GetPerpendicular(pBeg, pEnd, ringCenterVector);

            double radius = GetNativeRingRadius(ring, bondLength);
            double newRingPerpendicular = Math.Sqrt(Math.Pow(radius, 2) - Math.Pow(bondLength / 2, 2));

            ringCenterVector = Vector2.Normalize(ringCenterVector);
            Debug.WriteLine($"placeFusedRing->: ringCenterVector.Length {ringCenterVector.Length()}");
            ringCenterVector *= newRingPerpendicular;
            Vector2 ringCenter = GetMidPoint(pBeg, pEnd);

            ringCenter += ringCenterVector;

            Vector2 originRingCenterVector = ringCenter;

            pBeg -= originRingCenterVector;
            pEnd -= originRingCenterVector;

            double occupiedAngle = Angle(pBeg, pEnd);

            double remainingAngle = (2 * Math.PI) - occupiedAngle;
            double addAngle       = remainingAngle / (ring.RingSize - 1);

            Debug.WriteLine("placeFusedRing->occupiedAngle: " + Vectors.RadianToDegree(occupiedAngle));
            Debug.WriteLine("placeFusedRing->remainingAngle: " + Vectors.RadianToDegree(remainingAngle));
            Debug.WriteLine("placeFusedRing->addAngle: " + Vectors.RadianToDegree(addAngle));

            IAtom startAtom;

            double centerX = ringCenter.X;
            double centerY = ringCenter.Y;

            double xDiff = beg.Point2D.Value.X - end.Point2D.Value.X;
            double yDiff = beg.Point2D.Value.Y - end.Point2D.Value.Y;

            double startAngle;;

            int direction = 1;

            // if bond is vertical
            if (xDiff == 0)
            {
                Debug.WriteLine("placeFusedRing->Bond is vertical");
                //starts with the lower Atom
                if (beg.Point2D.Value.Y > end.Point2D.Value.Y)
                {
                    startAtom = beg;
                }
                else
                {
                    startAtom = end;
                }

                //changes the drawing direction
                if (centerX < beg.Point2D.Value.X)
                {
                    direction = 1;
                }
                else
                {
                    direction = -1;
                }
            }

            // if bond is not vertical
            else
            {
                //starts with the left Atom
                if (beg.Point2D.Value.X > end.Point2D.Value.X)
                {
                    startAtom = beg;
                }
                else
                {
                    startAtom = end;
                }

                //changes the drawing direction
                if (centerY - beg.Point2D.Value.Y > (centerX - beg.Point2D.Value.X) * yDiff / xDiff)
                {
                    direction = 1;
                }
                else
                {
                    direction = -1;
                }
            }
            startAngle = GeometryUtil.GetAngle(startAtom.Point2D.Value.X - ringCenter.X, startAtom.Point2D.Value.Y - ringCenter.Y);

            IAtom currentAtom = startAtom;
            // determine first bond in Ring
            //        int k = 0;
            //        for (k = 0; k < ring.GetElectronContainerCount(); k++) {
            //            if (ring.GetElectronContainer(k) is IBond) break;
            //        }
            IBond currentBond = sharedAtoms.Bonds[0];
            var   atomsToDraw = new List <IAtom>();

            for (int i = 0; i < ring.Bonds.Count - 2; i++)
            {
                currentBond = ring.GetNextBond(currentBond, currentAtom);
                currentAtom = currentBond.GetOther(currentAtom);
                atomsToDraw.Add(currentAtom);
            }
            addAngle = addAngle * direction;

#if DEBUG
            Debug.WriteLine("placeFusedRing->startAngle: " + Vectors.RadianToDegree(startAngle));
            Debug.WriteLine("placeFusedRing->addAngle: " + Vectors.RadianToDegree(addAngle));
            Debug.WriteLine("placeFusedRing->startAtom is: " + (Molecule.Atoms.IndexOf(startAtom) + 1));
            Debug.WriteLine("AtomsToDraw: " + AtomPlacer.ListNumbers(Molecule, atomsToDraw));
#endif

            AtomPlacer.PopulatePolygonCorners(atomsToDraw, ringCenter, startAngle, addAngle, radius);
        }
Beispiel #2
0
        private void PlaceBridgedRing(IRing ring, IAtomContainer sharedAtoms, Vector2 sharedAtomsCenter, Vector2 ringCenterVector, double bondLength)
        {
            IAtom[]      bridgeAtoms = GetBridgeAtoms(sharedAtoms);
            IAtom        bondAtom1   = bridgeAtoms[0];
            IAtom        bondAtom2   = bridgeAtoms[1];
            List <IAtom> otherAtoms  = new List <IAtom>();

            foreach (IAtom atom in sharedAtoms.Atoms)
            {
                if (atom != bondAtom1 && atom != bondAtom2)
                {
                    otherAtoms.Add(atom);
                }
            }

            bool snap = ring.GetProperty <bool>(SnapHint, false);

            bool swap = snap ? Det(bondAtom1.Point2D.Value, GeometryUtil.Get2DCenter(otherAtoms), bondAtom2.Point2D.Value) < 0
                                : Det(bondAtom1.Point2D.Value, GeometryUtil.Get2DCenter(otherAtoms), bondAtom2.Point2D.Value) > 0;

            if (swap)
            {
                IAtom tmp = bondAtom1;
                bondAtom1 = bondAtom2;
                bondAtom2 = tmp;
            }

            Vector2 bondAtom1Vector = bondAtom1.Point2D.Value;
            Vector2 bondAtom2Vector = bondAtom2.Point2D.Value;

            Vector2 midPoint = GetMidPoint(bondAtom1Vector, bondAtom2Vector);
            Vector2 ringCenter;
            double  radius = GetNativeRingRadius(ring, bondLength);
            double  offset = 0;

            if (snap)
            {
                ringCenter       = midPoint;
                ringCenterVector = GetPerpendicular(bondAtom1Vector, bondAtom2Vector,
                                                    new Vector2(midPoint.X - sharedAtomsCenter.X, midPoint.Y - sharedAtomsCenter.Y));

                offset = 0;
                foreach (IAtom atom in otherAtoms)
                {
                    double dist = Vector2.Distance(atom.Point2D.Value, midPoint);
                    if (dist > offset)
                    {
                        offset = dist;
                    }
                }
            }
            else
            {
                ringCenter = sharedAtomsCenter;
            }

            Vector2.Normalize(ringCenterVector);
            ringCenterVector = ringCenterVector * (radius - offset);
            ringCenter      += ringCenterVector;

            bondAtom1Vector -= ringCenter;
            bondAtom2Vector -= ringCenter;

            int numUnplaced = ring.RingSize - sharedAtoms.Atoms.Count;

            double dot = bondAtom2Vector.X * bondAtom1Vector.X + bondAtom2Vector.Y * bondAtom1Vector.Y;
            double det = bondAtom2Vector.X * bondAtom1Vector.Y - bondAtom2Vector.Y * bondAtom1Vector.X;

            // theta remain/step
            double tRemain = Math.Atan2(det, dot);

            if (tRemain < 0)
            {
                tRemain = Math.PI + (Math.PI + tRemain);
            }
            double tStep = tRemain / (numUnplaced + 1);

            Debug.WriteLine($"placeBridgedRing->tRemain: {Vectors.RadianToDegree(tRemain)}");
            Debug.WriteLine($"placeBridgedRing->tStep: {Vectors.RadianToDegree(tStep)}");

            double startAngle;

            startAngle = GeometryUtil.GetAngle(bondAtom1.Point2D.Value.X - ringCenter.X, bondAtom1.Point2D.Value.Y - ringCenter.Y);

            IAtom currentAtom = bondAtom1;
            IBond currentBond = sharedAtoms.GetConnectedBonds(currentAtom).First();

            List <IAtom> atoms = new List <IAtom>();

            for (int i = 0; i < ring.Bonds.Count; i++)
            {
                currentBond = ring.GetNextBond(currentBond, currentAtom);
                currentAtom = currentBond.GetOther(currentAtom);
                if (!sharedAtoms.Contains(currentAtom))
                {
                    atoms.Add(currentAtom);
                }
            }

#if DEBUG
            Debug.WriteLine($"{nameof(PlaceBridgedRing)}->atomsToPlace: {AtomPlacer.ListNumbers(Molecule, atoms)}");
            Debug.WriteLine($"{nameof(PlaceBridgedRing)}->startAngle: {Vectors.RadianToDegree(startAngle)}");
            Debug.WriteLine($"{nameof(PlaceBridgedRing)}->tStep: {Vectors.RadianToDegree(tStep)}");
#endif
            AtomPlacer.PopulatePolygonCorners(atoms, ringCenter, startAngle, -tStep, radius);
        }