Esempio n. 1
0
        public T[] GetSamples(int count)
        {
            lock (_lock)
            {
                //TODO: May want to consider when count > one of these lists.  But probably not

                // This is used when the front of the list should be favored
                Random rand     = StaticRandom.GetRandomForThread();
                var    randFunc = new Func <int, int, int>((min, max) => min + UtilityCore.GetIndexIntoList(rand.NextPow(2), max - min));

                if (_longTermIndex < 0 && _tentativeBuffer.Count == 0)
                {
                    // Empty
                    return(new T[0]);
                }
                else if (_longTermIndex >= _abandonTentativeSize)
                {
                    #region all from longterm

                    return(UtilityCore.RandomRange(0, _longTermIndex + 1, count).       // the randrange function takes care of reducing count if greater than range
                           Select(o => _longTermBuffer[o].Item).
                           ToArray());

                    #endregion
                }
                else if (_longTermIndex < 0)
                {
                    #region all from tentative

                    // Don't pull uniform randomly from tentative.  Favor items at the front of the list
                    return(UtilityCore.RandomRange(0, _tentativeBuffer.Count, count, randFunc).
                           Select(o => _tentativeBuffer[o].Item).
                           ToArray());

                    #endregion
                }
                else
                {
                    #region mixture

                    // Pull from long term then tentative
                    return(UtilityCore.RandomRange(0, _longTermIndex + 1 + _tentativeBuffer.Count, count, randFunc).
                           Select(o =>
                    {
                        if (o <= _longTermIndex)
                        {
                            return _longTermBuffer[o].Item;
                        }
                        else
                        {
                            return _tentativeBuffer[o - (_longTermIndex + 1)].Item;
                        }
                    }).
                           ToArray());

                    #endregion
                }
            }
        }
Esempio n. 2
0
        private static Point3D[] GetVoronoiCtrlPoints(HullVoronoiExploder_ShotHit[] hits, ITriangle[] convexHull, int minCount, int maxCount, double aabbLen)
        {
            const int MIN = 5;

            Random rand = StaticRandom.GetRandomForThread();

            #region examine hits

            Tuple <int, double>[] hitsByLength = hits.
                                                 Select((o, i) => Tuple.Create(i, (o.Hit.Item2 - o.Hit.Item1).Length)).
                                                 OrderByDescending(o => o.Item2).
                                                 ToArray();

            double totalLength = hitsByLength.Sum(o => o.Item2);

            Tuple <int, double>[] hitsByPercentLength = hitsByLength.
                                                        Select(o => Tuple.Create(o.Item1, o.Item2 / totalLength)).
                                                        ToArray();

            #endregion

            #region define control point cones

            double entryRadius   = aabbLen * .05;
            double exitRadius    = aabbLen * .35;
            double maxAxisLength = aabbLen * .75;

            int count = hits.Length * 2;
            count += (totalLength / (aabbLen * .1)).ToInt_Round();

            if (count < minCount)
            {
                count = minCount;
            }
            else if (count > maxCount)
            {
                count = maxCount;
            }

            #endregion

            #region randomly pick control points

            // Keep adding rings around shots until the count is exceeded

            var sets       = new List <Tuple <int, List <Point3D> > >();
            int runningSum = 0;

            // Make sure each hit line gets some points
            for (int cntr = 0; cntr < hits.Length; cntr++)
            {
                AddToHitline(ref runningSum, sets, cntr, hits[cntr].Hit, entryRadius, exitRadius, maxAxisLength, rand);
            }

            // Now that all hit lines have points, randomly choose lines until count is exceeded
            while (runningSum < count)
            {
                var pointsPerLength = hitsByLength.
                                      Select(o =>
                {
                    var pointsForIndex = sets.FirstOrDefault(p => p.Item1 == o.Item1);
                    int countForIndex  = pointsForIndex == null ? 0 : pointsForIndex.Item2.Count;
                    return(Tuple.Create(o.Item1, countForIndex / o.Item2));
                }).
                                      OrderBy(o => o.Item2).
                                      ToArray();

                double sumRatio = pointsPerLength.Sum(o => o.Item2);

                var pointsPerLengthNormalized = pointsPerLength.
                                                Select(o => (o.Item1, o.Item2 / sumRatio)).
                                                ToArray();

                int index = UtilityCore.GetIndexIntoList(rand.NextPow(3), pointsPerLengthNormalized);

                AddToHitline(ref runningSum, sets, index, hits[index].Hit, entryRadius, exitRadius, maxAxisLength, rand);
            }

            #endregion

            #region remove excessive points

            while (runningSum > count)
            {
                var fractions = sets.
                                Select((o, i) => (i, o.Item2.Count.ToDouble() / runningSum.ToDouble())).
                                OrderByDescending(o => o.Item2).
                                ToArray();

                int fractionIndex = UtilityCore.GetIndexIntoList(rand.NextPow(1.5), fractions);     //nextPow will favor the front of the list, which is where the rings with the most points are
                int setIndex      = fractions[fractionIndex].Item1;

                sets[setIndex].Item2.RemoveAt(UtilityCore.GetIndexIntoList(rand.NextDouble(), sets[setIndex].Item2.Count));

                runningSum--;
            }

            #endregion

            #region ensure enough for voronoi algorithm

            List <Point3D> retVal = new List <Point3D>();
            retVal.AddRange(sets.SelectMany(o => o.Item2));

            // The voronoi algrorithm fails if there aren't at least 5 points (really should fix that).  So add points that are
            // way away from the hull.  This will make the voronoi algorithm happy, and won't affect the local results
            if (count < MIN)
            {
                retVal.AddRange(
                    Enumerable.Range(0, MIN - count).
                    Select(o => Math3D.GetRandomVector_Spherical_Shell(aabbLen * 20).ToPoint())
                    );
            }

            #endregion

            return(retVal.ToArray());
        }