示例#1
0
            public BrainBurden(int index, LinkItem[] brains, LinkItem[] io)
            {
                this.Index = index;
                this.Brain = brains[index];
                this.Size = this.Brain.Size;

                _io = io;
            }
示例#2
0
        private static DistributeDistances GetDistances(LinkItem[] items1, LinkItem[] items2, ItemLinker_OverflowArgs overflowArgs)
        {
            // Distances between all item1s (not just delaunay, but all pairs)
            Tuple<int, double>[][] resistancesItem1 = ItemItemResistance(items1, overflowArgs == null ? 1 : overflowArgs.LinkResistanceMult);

            // Figure out the distances between 2s and 1s
            var distances2to1 = Enumerable.Range(0, items2.Length).
                Select(o => new Distances2to1
                (
                    o,
                    Enumerable.Range(0, items1.Length).
                        Select(p => Tuple.Create(p, (items1[p].Position - items2[o].Position).Length)).        //Item1=items1 index, Item2=distance to item1
                        OrderBy(p => p.Item2).      // first item1 needs to be the shortest distance
                        ToArray()
                )).
                OrderBy(o => o.DistancesTo1.First().Item2).
                ToArray();

            return new DistributeDistances(resistancesItem1, distances2to1);
        }
示例#3
0
        private static Tuple<int, double>[][] ItemItemResistance(LinkItem[] items, double linkResistanceMult)
        {
            // Get the AABB, and use the diagonal as the size
            var aabb = Math3D.GetAABB(items.Select(o => o.Position));
            double maxDistance = (aabb.Item2 - aabb.Item1).Length;

            // Get links between the items and distances of each link
            var links2 = UtilityCore.GetPairs(items.Length).
                Select(o =>
                {
                    double distance = (items[o.Item1].Position - items[o.Item2].Position).Length;
                    double resistance = (distance / maxDistance) * linkResistanceMult;

                    return Tuple.Create(o.Item2, o.Item1, resistance);
                }).
                ToArray();

            Tuple<int, double>[][] retVal = new Tuple<int, double>[items.Length][];

            for (int cntr = 0; cntr < items.Length; cntr++)
            {
                // Store all links for this item
                retVal[cntr] = links2.
                    Where(o => o.Item1 == cntr || o.Item2 == cntr).       // find links between this item and another
                    Select(o => Tuple.Create(o.Item1 == cntr ? o.Item2 : o.Item1, o.Item3)).     // store the link to the other item and the resistance
                    OrderBy(o => o.Item2).
                    ToArray();
            }

            return retVal;
        }
示例#4
0
        private static Tuple<int, int>[] Link12_Extra(Tuple<int, int>[] initial, LinkItem[] items1, LinkItem[] items2, DistributeDistances distances, ItemLinker_ExtraArgs extraArgs)
        {
            Random rand = StaticRandom.GetRandomForThread();

            int wholePercent = extraArgs.Percent.ToInt_Floor();

            List<int> addOrder = new List<int>();

            if (extraArgs.BySize)
            {
                double totalSize = items2.Sum(o => o.Size);
                double maxSize = extraArgs.Percent * totalSize;
                double usedSize = 0;

                if (extraArgs.EvenlyDistribute)
                {
                    #region by size, evenly distribute

                    // Add some complete passes if over 100% percent
                    for (int cntr = 0; cntr < wholePercent; cntr++)
                    {
                        addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length));
                    }

                    usedSize = wholePercent * totalSize;

                    #endregion
                }

                #region by size, distribute the rest

                //NOTE: Building this list by size so that larger items have a higher chance of being chosen
                var bySize = items2.
                    Select((o, i) => Tuple.Create(i, o.Size / totalSize)).
                    OrderByDescending(o => o.Item2).
                    ToArray();

                // Keep selecting items unti the extra size is consumed (or if no more can be added)
                while (true)
                {
                    bool foundOne = false;

                    for (int cntr = 0; cntr < 1000; cntr++)     // this is an infinite loop detector
                    {
                        int attemptIndex = UtilityCore.GetIndexIntoList(rand.NextDouble(), bySize);     // get the index into the list that the rand percent represents
                        attemptIndex = bySize[attemptIndex].Item1;      // get the index into items2

                        if (items2[attemptIndex].Size + usedSize <= maxSize)
                        {
                            foundOne = true;
                            usedSize += items2[attemptIndex].Size;
                            addOrder.Add(attemptIndex);
                            break;
                        }
                    }

                    if (!foundOne)
                    {
                        // No more will fit
                        break;
                    }
                }

                #endregion
            }
            else
            {
                if (extraArgs.EvenlyDistribute)
                {
                    #region ignore size, evenly distribute

                    // Add some complete passes if over 100% percent
                    for (int cntr = 0; cntr < wholePercent; cntr++)
                    {
                        addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length));
                    }

                    // Add some items based on the portion of percent that is less than 100%
                    int remainder = (items2.Length * (extraArgs.Percent - wholePercent)).
                        ToInt_Round();

                    addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length, remainder));

                    #endregion
                }
                else
                {
                    #region ignore size, randomly distribute

                    int totalCount = (items2.Length * extraArgs.Percent).
                        ToInt_Round();

                    //NOTE: UtilityCore.RandomRange stops when the list is exhausted, and makes sure not to have dupes.  That's not what is wanted
                    //here.  Just randomly pick X times
                    addOrder.AddRange(Enumerable.Range(0, totalCount).Select(o => rand.Next(items2.Length)));

                    #endregion
                }
            }

            return AddLinks(items1, items2, distances, addOrder, initial);
        }
示例#5
0
        /// <summary>
        /// This adds 2s to 1s one at a time (specified by distances2to1_AddOrder)
        /// </summary>
        private static Tuple<int, int>[] AddLinks(LinkItem[] items1, LinkItem[] items2, DistributeDistances distances, IEnumerable<int> distances2to1_AddOrder, Tuple<int, int>[] initial = null)
        {
            // Store the inital link burdens
            BrainBurden[] links = Enumerable.Range(0, items1.Length).
                Select(o => new BrainBurden(o, items1, items2)).
                ToArray();

            if (initial != null)
            {
                #region Store initial

                foreach (var set in initial.ToLookup(o => o.Item1))
                {
                    foreach (int item2Index in set.Select(o => o.Item2))
                    {
                        links[set.Key].AddIOLink(item2Index);
                    }
                }

                #endregion
            }

            foreach (var distanceIO in distances2to1_AddOrder.Select(o => distances.Distances2to1[o]))
            {
                int ioIndex = distanceIO.Index2;
                int closestBrainIndex = distanceIO.DistancesTo1[0].Item1;

                AddIOLink(links, ioIndex, items2[ioIndex].Size, closestBrainIndex, distances.ResistancesItem1[closestBrainIndex]);
            }

            // Build the return
            List<Tuple<int, int>> retVal = new List<Tuple<int, int>>();
            foreach (BrainBurden burden in links)
            {
                retVal.AddRange(burden.IOLinks.Select(o => Tuple.Create(burden.Index, o)));
            }

            return retVal.ToArray();
        }
示例#6
0
        /// <summary>
        /// This links closest items together
        /// </summary>
        private static Tuple<int, int>[] Link12_Closest(LinkItem[] items1, LinkItem[] items2)
        {
            var retVal = new Tuple<int, int>[items2.Length];

            for (int cntr = 0; cntr < items2.Length; cntr++)
            {
                int closest = items1.
                    Select((o, i) => new { Index = i, Position = o.Position, DistSqr = (o.Position - items2[cntr].Position).LengthSquared }).
                    OrderBy(o => o.DistSqr).
                    First().
                    Index;

                retVal[cntr] = Tuple.Create(closest, cntr);
            }

            return retVal;
        }
示例#7
0
        private static Tuple<int, int>[] Link12_Distribute(LinkItem[] items1, LinkItem[] items2, DistributeDistances distances)
        {
            IEnumerable<int> addOrder = Enumerable.Range(0, distances.Distances2to1.Length);

            return AddLinks(items1, items2, distances, addOrder);
        }
示例#8
0
        /// <summary>
        /// Every item in 2 will have at least one link to a 1.  There could be some item1s that don't have a link
        /// </summary>
        /// <param name="overflowArgs">
        /// Item2s get matched to the nearest Item1.
        /// If this args is null then, it stays that way.
        /// If this is populated, then links will move from burdened item1s to less burdened
        /// </param>
        /// <returns>
        /// Item1=index into item1 list
        /// Item2=index into item2 list
        /// </returns>
        public static Tuple<int, int>[] Link_1_2(LinkItem[] items1, LinkItem[] items2, ItemLinker_OverflowArgs overflowArgs = null, ItemLinker_ExtraArgs extraArgs = null)
        {
            if (items1 == null || items2 == null || items1.Length == 0 || items2.Length == 0)
            {
                return new Tuple<int, int>[0];
            }

            Tuple<int, int>[] retVal = null;

            if (overflowArgs == null)
            {
                // Just link to the closest
                retVal = Link12_Closest(items1, items2);
            }

            if (overflowArgs == null && extraArgs == null)
            {
                // Nothing special to do, exit early
                return retVal;
            }

            DistributeDistances distances = GetDistances(items1, items2, overflowArgs);

            if (overflowArgs != null)
            {
                // Consider item1s burden when linking them
                retVal = Link12_Distribute(items1, items2, distances);
            }

            if (extraArgs != null)
            {
                // Add more links
                retVal = Link12_Extra(retVal, items1, items2, distances, extraArgs);
            }

            return retVal;
        }
示例#9
0
        private static LinkSetPair[] PruneLinks(TriangleIndexed[] triangles, SortedList<Tuple<int, int>, double> all, LinkItem[] brains, ItemLinker_CombineArgs args)
        {
            List<Tuple<int[], int[]>> retVal = all.Keys.
                Select(o => Tuple.Create(new[] { o.Item1 }, new[] { o.Item2 })).
                ToList();

            foreach (TriangleIndexed triangle in triangles)
            {
                Tuple<bool, TriangleEdge> changeEdge = PruneLinks_LongThin(triangle, all, args);
                if (changeEdge == null)
                {
                    continue;
                }

                if (changeEdge.Item1)
                {
                    PruneLinks_Merge(triangle, changeEdge.Item2, retVal);
                }
                else
                {
                    PruneLinks_Remove(triangle, changeEdge.Item2, retVal);
                }
            }

            return retVal.Select(o => new LinkSetPair(o.Item1, o.Item2, brains)).ToArray();
        }
示例#10
0
 public LinkSetPair(IEnumerable<int> set1, IEnumerable<int> set2, LinkItem[] all)
     : this(new LinkSet(set1, all), new LinkSet(set2, all)) { }
示例#11
0
        /// <summary>
        /// Link brains to each other (delaunay graph, then prune thin triangles)
        /// </summary>
        /// <param name="all">
        /// Item1=Link between two items (sub item1 and 2 are the indices)
        /// Item2=Distance between those two items
        /// </param>
        /// <param name="final">
        /// This holds a set of links after the thin triangles are pruned.  There's a chance of items being merged
        /// </param>
        public static void Link_Self(out SortedList<Tuple<int, int>, double> all, out LinkSetPair[] final, LinkItem[] items, ItemLinker_CombineArgs combineArgs = null)
        {
            TriangleIndexed[] triangles;
            GetItemDelaunay(out all, out triangles, items);

            if (items.Length < 2)
            {
                //throw new ArgumentException("This method requires at least two brains: " + items.Length.ToString());
                final = new LinkSetPair[0];
                return;
            }

            // Prune links that don't make sense
            if (combineArgs != null && triangles.Length > 0)
            {
                final = PruneLinks(triangles, all, items, combineArgs);
            }
            else
            {
                final = all.Keys.
                    Select(o => new LinkSetPair(o.Item1, o.Item2, items)).
                    ToArray();
            }
        }
示例#12
0
 public LinkSetPair(int item1, int item2, LinkItem[] all)
     : this(new LinkSet(item1, all), new LinkSet(item2, all)) { }
示例#13
0
        public LinkSet(IEnumerable<int> indices, LinkItem[] all)
        {
            this.Indices = indices.ToArray();
            this.Items = this.Indices.Select(o => all[o]).ToArray();

            this.Positions = this.Items.Select(o => o.Position).ToArray();

            if (this.Items.Length == 1)
            {
                this.Center = this.Items[0].Position;
            }
            else
            {
                this.Center = Math3D.GetCenter(this.Positions);
            }
        }
示例#14
0
 public LinkSet(int index, LinkItem[] all)
     : this(new[] { index }, all) { }
示例#15
0
        //NOTE: This makes sure that key.item1 is less than key.item2
        private static SortedList<Tuple<int, int>, double> GetLengths(Tuple<int, int>[] keys, LinkItem[] items)
        {
            SortedList<Tuple<int, int>, double> retVal = new SortedList<Tuple<int, int>, double>();

            foreach (Tuple<int, int> key in keys.Select(o => o.Item1 < o.Item2 ? o : Tuple.Create(o.Item2, o.Item1)))
            {
                double distance = (items[key.Item1].Position - items[key.Item2].Position).Length;

                retVal.Add(key, distance);
            }

            return retVal;
        }
示例#16
0
        private static void GetItemDelaunay(out SortedList<Tuple<int, int>, double> segments, out TriangleIndexed[] triangles, LinkItem[] items)
        {
            Tuple<int, int>[] links = null;

            if (items.Length < 2)
            {
                links = new Tuple<int, int>[0];
                triangles = new TriangleIndexed[0];
            }
            else if (items.Length == 2)
            {
                links = new[] { Tuple.Create(0, 1) };
                triangles = new TriangleIndexed[0];
            }
            else if (items.Length == 3)
            {
                links = new[] 
                    {
                        Tuple.Create(0, 1),
                        Tuple.Create(0, 2),
                        Tuple.Create(1, 2),
                    };

                triangles = new[] { new TriangleIndexed(0, 1, 2, items.Select(o => o.Position).ToArray()) };
            }
            else
            {
                Tetrahedron[] tetras = Math3D.GetDelaunay(items.Select(o => o.Position).ToArray());
                links = Tetrahedron.GetUniqueLines(tetras);
                triangles = Tetrahedron.GetUniqueTriangles(tetras);
            }

            segments = GetLengths(links, items);
        }