Beispiel #1
0
        /// <summary>
        /// Generate a 2D directional vector that is located in the middle of the largest angular extent
        /// (i.e. has the most space). For example if we have a two vectors, one pointing up and one
        /// pointing right we have to extents (.5π and 1.5π). The new vector would be pointing down and
        /// to the left in the middle of the 1.5π extent.
        /// </summary>
        /// <param name="vectors">list of vectors</param>
        /// <returns>the new vector</returns>
        public static Vector2 NewVectorInLargestGap(IList <Vector2> vectors)
        {
            Debug.Assert(vectors.Count > 1);
            double[] extents = VecmathUtil.Extents(vectors);
            Array.Sort(extents);

            // find and store the index of the largest extent
            double max   = -1;
            int    index = -1;

            for (int i = 0; i < vectors.Count; i++)
            {
                double extent = extents[(i + 1) % vectors.Count] - extents[i];
                if (extent < 0)
                {
                    extent += TAU;
                }
                if (extent > max)
                {
                    max   = extent;
                    index = i;
                }
            }

            Debug.Assert(index >= 0);

            double mid   = (max / 2);
            double theta = extents[index] + mid;

            return(new Vector2(Math.Cos(theta), Math.Sin(theta)));
        }
Beispiel #2
0
        /// <summary>
        /// Using the angular extents of vectors, determine the best position for a hydrogen label. The
        /// position with the most space is selected first. If multiple positions have the same amount of
        /// space, the one where the hydrogen position is most centred is selected. If all position are
        /// okay, the priority is Right > Left > Above > Below.
        /// </summary>
        /// <param name="vectors">directional vectors for each bond from an atom</param>
        /// <returns>best hydrogen position</returns>
        internal static HydrogenPosition UsingAngularExtent(IList <Vector2> vectors)
        {
            var extents = VecmathUtil.Extents(vectors);

            Array.Sort(extents);

            var extentMap = new Dictionary <HydrogenPosition, OffsetExtent>();

            for (int i = 0; i < extents.Length; i++)
            {
                double before = extents[i];
                double after  = extents[(i + 1) % extents.Length];

                foreach (var position in Values)
                {
                    // adjust the extents such that this position is '0'
                    double bias       = Tau - V[(int)position].Direction;
                    double afterBias  = after + bias;
                    double beforeBias = before + bias;

                    // ensure values are 0 <= x < Tau
                    if (beforeBias >= Tau)
                    {
                        beforeBias -= Tau;
                    }
                    if (afterBias >= Tau)
                    {
                        afterBias -= Tau;
                    }

                    // we can now determine the extents before and after this
                    // hydrogen position
                    double afterExtent  = afterBias;
                    double beforeExtent = Tau - beforeBias;

                    // the total extent is amount of space between these two bonds
                    // when sweeping round. The offset is how close this hydrogen
                    // position is to the center of the extent.
                    double totalExtent = afterExtent + beforeExtent;
                    double offset      = Math.Abs(totalExtent / 2 - beforeExtent);

                    // for each position keep the one with the smallest extent this is
                    // the most space available without another bond getting in the way
                    if (!extentMap.TryGetValue(position, out OffsetExtent offsetExtent) || totalExtent < offsetExtent.Extent)
                    {
                        extentMap[position] = new OffsetExtent(totalExtent, offset);
                    }
                }
            }

            // we now have the offset extent for each position that we can sort and prioritise
            var extentEntries = extentMap;
            KeyValuePair <HydrogenPosition, OffsetExtent>?best = null;

            foreach (var e in extentEntries)
            {
                if (best == null || ExtentPriority.Instance.Compare(e, best.Value) < 0)
                {
                    best = e;
                }
            }

            Debug.Assert(best != null);
            return(best.Value.Key);
        }