private void btn3DLinksBrainBrain_Click(object sender, RoutedEventArgs e) { try { PrepFor3D(); ClearTempVisuals(); if (_brains3D.Count == 0) { return; } LinkItem[] brains = _brains3D. Select(o => new LinkItem(o.Position.Value, o.Size)). ToArray(); ItemLinker_CombineArgs combineArgs = new ItemLinker_CombineArgs() { //Ratio_Skinny = .3, //Ratio_Wide = .88, //MergeChance = 0, }; SortedList<Tuple<int, int>, double> all; LinkSetPair[] final; ItemLinker.Link_Self(out all, out final, brains, combineArgs); #region Draw if (final != null) { foreach (var link in final) { // Group From if (link.Set1.Items.Length > 1) { _linksBrain3D.Add(DrawBrainGroup(_viewportFull, link.Set1.Positions, link.Set2.Center, _brainGroupColor)); } // Group To if (link.Set2.Items.Length > 1) { _linksBrain3D.Add(DrawBrainGroup(_viewportFull, link.Set2.Positions, link.Set2.Center, _brainGroupColor)); } // Link Visual3D visual = AddLine(_viewportFull, link.Set1.Center, link.Set2.Center, _brainLinkColor); _linksBrain3D.Add(new Item3D(visual, 0, new[] { link.Set1.Center, link.Set2.Center })); } } #endregion } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
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(); }
/// <summary> /// If this triangle is long and thin, then this will decide whether to remove a link, or merge the two close brains /// </summary> /// <returns> /// Null : This is not a long thin triangle. Move along /// Item1=True : Merge the two brains connected by Item2 /// Item1=False : Remove the Item2 link /// </returns> private static Tuple<bool, TriangleEdge> PruneLinks_LongThin(ITriangleIndexed triangle, SortedList<Tuple<int, int>, double> all, ItemLinker_CombineArgs args) { var lengths = new[] { TriangleEdge.Edge_01, TriangleEdge.Edge_12, TriangleEdge.Edge_20 }. Select(o => new { Edge = o, Length = GetLength(triangle, o, all) }). OrderBy(o => o.Length). ToArray(); //NOTE: The order of these if statements is important. I ran into a case where it's both wide and //skinny (nearly colinear). In that case, the long segment should be removed if (lengths[2].Length / (lengths[0].Length + lengths[1].Length) > args.Ratio_Wide) { // Wide base (small angles, one huge angle) return Tuple.Create(false, lengths[2].Edge); } else if (lengths[0].Length / lengths[1].Length < args.Ratio_Skinny && lengths[0].Length / lengths[2].Length < args.Ratio_Skinny) { #region Isosceles - skinny base if (StaticRandom.NextDouble() < args.MergeChance) { // Treat the two close brains like one, and split the links evenly with the far brain return Tuple.Create(true, lengths[0].Edge); } else { // Choose one of the long links to remove if (StaticRandom.NextBool()) { return Tuple.Create(false, lengths[1].Edge); } else { return Tuple.Create(false, lengths[2].Edge); } } #endregion } return null; }
/// <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(); } }