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; }
/// <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; }
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); }
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); }