/// <summary> /// This creates solid colored blobs with areas proportional to the number of items contained. When the user /// mouses over a blob, the caller can show examples of the items as tooltips /// </summary> public static void ShowResults2D_Blobs(Border border, SOMResult result, Func <SOMNode, Color> getNodeColor, BlobEvents events = null) { #region validate #if DEBUG if (!result.Nodes.All(o => o.Position.Size == 2)) { throw new ArgumentException("Node positions need to be 2D"); } #endif #endregion Point[] points = result.Nodes. Select(o => new Point(o.Position[0], o.Position[1])). ToArray(); VoronoiResult2D voronoi = Math2D.GetVoronoi(points, true); voronoi = Math2D.CapVoronoiCircle(voronoi); Color[] colors = result.Nodes. Select(o => getNodeColor(o)). ToArray(); //ISOMInput[][] inputsByNode = UtilityCore.ConvertJaggedArray<ISOMInput>(result.InputsByNode); Vector size = new Vector(border.ActualWidth - border.Padding.Left - border.Padding.Right, border.ActualHeight - border.Padding.Top - border.Padding.Bottom); Canvas canvas = DrawVoronoi_Blobs(voronoi, colors, result.Nodes, result.InputsByNode, size.X.ToInt_Floor(), size.Y.ToInt_Floor(), events); border.Child = canvas; }
private static Point[][] GetPolygons(VoronoiResult2D voronoi, Vector offset) { Point[][] retVal = new Point[voronoi.ControlPoints.Length][]; for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { retVal[cntr] = voronoi.GetPolygon(cntr, 1). // don't need to worry about ray length, they are all segments Select(o => o + offset). // shifting the points by offset ToArray(); } return(retVal); }
private static double[] AnalyzeVoronoiCellSizes(VoronoiResult2D voronoi, ISOMInput[][] imagesByNode) { // Calculate area, density of each node var sizes = Enumerable.Range(0, voronoi.ControlPoints.Length). Select(o => { double area = Math2D.GetAreaPolygon(voronoi.GetPolygon(o, 1)); // there are no rays double imageCount = imagesByNode[o].Length.ToDouble(); return(new { ImagesCount = imageCount, Area = area, Density = imageCount / area, }); }). ToArray(); // Don't let any node have an area smaller than this double minArea = sizes.Min(o => o.Area) * .2; // Find the node with the largest density. This is the density to use when drawing all cells var largestDensity = sizes. OrderByDescending(o => o.Density). First(); return(sizes.Select(o => { // Figure out how much area it would take using the highest density double area = o.ImagesCount / largestDensity.Density; if (area < minArea) { area = minArea; } return area; }). ToArray()); }
/// <summary> /// This divides the border up into a voronoi, then each node is tiled with examples /// </summary> public static void ShowResults2D_Tiled(Border border, SOMResult result, int tileWidth, int tileHeight, Action <DrawTileArgs> drawTile, BlobEvents events = null) { //TODO: Take a func that will render the input onto a writable bitmap, or something dynamic but efficient? // or take these in? //int tileWidth, int tileHeight Point[] points = result.Nodes. Select(o => new Point(o.Position[0], o.Position[1])). ToArray(); Vector size = new Vector(border.ActualWidth - border.Padding.Left - border.Padding.Right, border.ActualHeight - border.Padding.Top - border.Padding.Bottom); VoronoiResult2D voronoi = Math2D.GetVoronoi(points, true); voronoi = Math2D.CapVoronoiCircle(voronoi); //voronoi = Math2D.CapVoronoiRectangle(voronoi, aspectRatio: 1d); //TODO: Implement this Canvas canvas = DrawVoronoi_Tiled(voronoi, result.Nodes, result.InputsByNode, size.X.ToInt_Floor(), size.Y.ToInt_Floor(), tileWidth, tileHeight, drawTile, events); border.Child = canvas; }
internal static void CreateNeurons(out Neuron_SensorPosition[] neuronsR, out Neuron_SensorPosition[] neuronsG, out Neuron_SensorPosition[] neuronsB, out OverlayResult[][] overlayR, out OverlayResult[][] overlayG, out OverlayResult[][] overlayB, out int pixelWidthHeight, ShipPartDNA dna, ItemOptions itemOptions, double neuronDensity) { const int MINPIXELWIDTH = 16; #region Calculate counts // Figure out how many neurons to make //NOTE: This radius isn't taking SCALE into account. The other neural parts do this as well, so the neural density properties can be more consistent double radius = (dna.Scale.X + dna.Scale.Y + dna.Scale.Z) / (3d * 2d); // xyz should all be the same anyway double area = Math.Pow(radius, itemOptions.Sensor_NeuronGrowthExponent); int neuronCount = Convert.ToInt32(Math.Ceiling(neuronDensity * area)); if (neuronCount == 0) { neuronCount = 1; } // Figure out how many pixels to make pixelWidthHeight = neuronCount / 9; // dividing by 3 to get the number of neurons in a single plate. divide that by 3, because that's a good ratio of neuron cells to pixels if (pixelWidthHeight < MINPIXELWIDTH) { pixelWidthHeight = MINPIXELWIDTH; } #endregion #region Neurons // Place them evenly in a sphere //NOTE: An interesting side effect of calling this for each generation is that the parent may not have been perfectly evenly spaced, but calling this //again will slightly refine the positions Vector3D[][] positions = GetNeuronPositions(dna.Neurons, neuronCount, 3, radius); // Create neurons neuronsR = positions[0].Select(o => new Neuron_SensorPosition(o.ToPoint(), true)).ToArray(); neuronsG = positions[1].Select(o => new Neuron_SensorPosition(o.ToPoint(), true)).ToArray(); neuronsB = positions[2].Select(o => new Neuron_SensorPosition(o.ToPoint(), true)).ToArray(); #endregion #region Polygons around neurons // Figure out which pixels each neuron intersects with VoronoiResult2D[] voronoi = new VoronoiResult2D[3]; voronoi[0] = Math2D.CapVoronoiCircle(Math2D.GetVoronoi(positions[0].Select(o => new Point(o.X, o.Y)).ToArray(), true)); voronoi[1] = Math2D.CapVoronoiCircle(Math2D.GetVoronoi(positions[1].Select(o => new Point(o.X, o.Y)).ToArray(), true)); voronoi[2] = Math2D.CapVoronoiCircle(Math2D.GetVoronoi(positions[2].Select(o => new Point(o.X, o.Y)).ToArray(), true)); #region Figure out the extremes Point[] allEdgePoints = voronoi.SelectMany(o => o.EdgePoints).ToArray(); Point min = new Point(allEdgePoints.Min(o => o.X), allEdgePoints.Min(o => o.Y)); Point max = new Point(allEdgePoints.Max(o => o.X), allEdgePoints.Max(o => o.Y)); double width = max.X - min.X; double height = max.Y - min.Y; // Enlarge a bit min.X -= width * .05d; min.Y -= height * .05d; max.X += width * .05d; max.Y += height * .05d; width = max.X - min.X; height = max.Y - min.Y; Vector offset = new Vector(-min.X, -min.Y); #endregion // Figure out which pixels each polygon overlaps overlayR = GetIntersections(new Size(width, height), pixelWidthHeight, pixelWidthHeight, GetPolygons(voronoi[0], offset)); overlayG = GetIntersections(new Size(width, height), pixelWidthHeight, pixelWidthHeight, GetPolygons(voronoi[1], offset)); overlayB = GetIntersections(new Size(width, height), pixelWidthHeight, pixelWidthHeight, GetPolygons(voronoi[2], offset)); #endregion }
private static Canvas DrawVoronoi_Tiled(VoronoiResult2D voronoi, SOMNode[] nodes, ISOMInput[][] images, int imageWidth, int imageHeight, int tileWidth, int tileHeight, Action <DrawTileArgs> drawTile, BlobEvents events) { #region transform var aabb = Math2D.GetAABB(voronoi.EdgePoints); TransformGroup transform = new TransformGroup(); transform.Children.Add(new TranslateTransform(-aabb.Item1.X, -aabb.Item1.Y)); transform.Children.Add(new ScaleTransform(imageWidth / (aabb.Item2.X - aabb.Item1.X), imageHeight / (aabb.Item2.Y - aabb.Item1.Y))); #endregion Canvas retVal = new Canvas(); for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { #region polygon Polygon polygon = new Polygon(); if (voronoi.EdgesByControlPoint[cntr].Length < 3) { throw new ApplicationException("Expected at least three edge points"); } Edge2D[] edges = voronoi.EdgesByControlPoint[cntr].Select(o => voronoi.Edges[o]).ToArray(); Point[] edgePoints = Edge2D.GetPolygon(edges, 1d); edgePoints = edgePoints. Select(o => transform.Transform(o)). ToArray(); foreach (Point point in edgePoints) { polygon.Points.Add(point); } polygon.Fill = GetTiledSamples(edgePoints, images[cntr], nodes[cntr], tileWidth, tileHeight, drawTile); polygon.Stroke = new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192)); polygon.StrokeThickness = 2; polygon.Tag = Tuple.Create(nodes[cntr], images[cntr]); if (events != null) { if (events.MouseMove != null && events.MouseLeave != null) { polygon.MouseMove += Polygon2D_MouseMove; polygon.MouseLeave += Polygon2D_MouseLeave; } if (events.Click != null) { polygon.MouseUp += Polygon_MouseUp; } } retVal.Children.Add(polygon); #endregion } return(retVal); }
private static Canvas DrawVoronoi_Blobs(VoronoiResult2D voronoi, Color[] colors, SOMNode[] nodes, ISOMInput[][] inputsByNode, int imageWidth, int imageHeight, BlobEvents events) { const double MARGINPERCENT = 1.05; // Analyze size ratios double[] areas = AnalyzeVoronoiCellSizes(voronoi, inputsByNode); #region transform var aabb = Math2D.GetAABB(voronoi.EdgePoints); aabb = Tuple.Create((aabb.Item1.ToVector() * MARGINPERCENT).ToPoint(), (aabb.Item2.ToVector() * MARGINPERCENT).ToPoint()); TransformGroup transform = new TransformGroup(); transform.Children.Add(new TranslateTransform(-aabb.Item1.X, -aabb.Item1.Y)); transform.Children.Add(new ScaleTransform(imageWidth / (aabb.Item2.X - aabb.Item1.X), imageHeight / (aabb.Item2.Y - aabb.Item1.Y))); #endregion Canvas retVal = new Canvas(); retVal.Effect = new DropShadowEffect() { Color = Colors.Gray, Opacity = .2, BlurRadius = 5, Direction = 0, ShadowDepth = 0, }; for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { #region polygon Polygon polygon = new Polygon(); if (voronoi.EdgesByControlPoint[cntr].Length < 3) { throw new ApplicationException("Expected at least three edge points"); } Edge2D[] edges = voronoi.EdgesByControlPoint[cntr].Select(o => voronoi.Edges[o]).ToArray(); Point[] edgePoints = Edge2D.GetPolygon(edges, 1d); // Resize to match the desired area edgePoints = ResizeConvexPolygon(edgePoints, areas[cntr]); // Convert into a smooth blob BezierSegment3D[] bezier = BezierUtil.GetBezierSegments(edgePoints.Select(o => o.ToPoint3D()).ToArray(), .25, true); edgePoints = BezierUtil.GetPath(75, bezier). Select(o => o.ToPoint2D()). ToArray(); // Transform to canvas coords edgePoints = edgePoints. Select(o => transform.Transform(o)). ToArray(); foreach (Point point in edgePoints) { polygon.Points.Add(point); } polygon.Fill = new SolidColorBrush(colors[cntr]); polygon.Stroke = null; // new SolidColorBrush(UtilityWPF.OppositeColor(colors[cntr], false)); polygon.StrokeThickness = 1; polygon.Tag = Tuple.Create(events, nodes[cntr], inputsByNode[cntr]); if (events != null) { if (events.MouseMove != null && events.MouseLeave != null) { polygon.MouseMove += Polygon2D_MouseMove; polygon.MouseLeave += Polygon2D_MouseLeave; } if (events.Click != null) { polygon.MouseUp += Polygon_MouseUp; } } retVal.Children.Add(polygon); #endregion } return(retVal); }
private static Canvas DrawVoronoi_Tiled(VoronoiResult2D voronoi, SOMNode[] nodes, ISOMInput[][] images, int imageWidth, int imageHeight, int tileWidth, int tileHeight, Action<DrawTileArgs> drawTile, BlobEvents events) { #region transform var aabb = Math2D.GetAABB(voronoi.EdgePoints); TransformGroup transform = new TransformGroup(); transform.Children.Add(new TranslateTransform(-aabb.Item1.X, -aabb.Item1.Y)); transform.Children.Add(new ScaleTransform(imageWidth / (aabb.Item2.X - aabb.Item1.X), imageHeight / (aabb.Item2.Y - aabb.Item1.Y))); #endregion Canvas retVal = new Canvas(); for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { #region polygon Polygon polygon = new Polygon(); if (voronoi.EdgesByControlPoint[cntr].Length < 3) { throw new ApplicationException("Expected at least three edge points"); } Edge2D[] edges = voronoi.EdgesByControlPoint[cntr].Select(o => voronoi.Edges[o]).ToArray(); Point[] edgePoints = Edge2D.GetPolygon(edges, 1d); edgePoints = edgePoints. Select(o => transform.Transform(o)). ToArray(); foreach (Point point in edgePoints) { polygon.Points.Add(point); } polygon.Fill = GetTiledSamples(edgePoints, images[cntr], nodes[cntr], tileWidth, tileHeight, drawTile); polygon.Stroke = new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192)); polygon.StrokeThickness = 2; polygon.Tag = Tuple.Create(nodes[cntr], images[cntr]); if (events != null) { if (events.MouseMove != null && events.MouseLeave != null) { polygon.MouseMove += Polygon2D_MouseMove; polygon.MouseLeave += Polygon2D_MouseLeave; } if (events.Click != null) { polygon.MouseUp += Polygon_MouseUp; } } retVal.Children.Add(polygon); #endregion } return retVal; }
private static double[] AnalyzeVoronoiCellSizes(VoronoiResult2D voronoi, ISOMInput[][] imagesByNode) { // Calculate area, density of each node var sizes = Enumerable.Range(0, voronoi.ControlPoints.Length). Select(o => { double area = Math2D.GetAreaPolygon(voronoi.GetPolygon(o, 1)); // there are no rays double imageCount = imagesByNode[o].Length.ToDouble(); return new { ImagesCount = imageCount, Area = area, Density = imageCount / area, }; }). ToArray(); // Don't let any node have an area smaller than this double minArea = sizes.Min(o => o.Area) * .2; // Find the node with the largest density. This is the density to use when drawing all cells var largestDensity = sizes. OrderByDescending(o => o.Density). First(); return sizes.Select(o => { // Figure out how much area it would take using the highest density double area = o.ImagesCount / largestDensity.Density; if (area < minArea) { area = minArea; } return area; }). ToArray(); }
private void btn2DCreateLinksSimple_Click(object sender, RoutedEventArgs e) { try { PrepFor2D(); ClearTempVisuals(); if (_brains2D.Count == 0) { return; } Point[] brainPositions = _brains2D.Select(o => o.Position).ToArray(); Point[] ioPositions = UtilityCore.Iterate(_inputs2D, _outputs2D).Select(o => o.Position).ToArray(); //TODO: Don't link every brain to every other brain. Maybe do a similar voronoi, and only link clusters //TODO: It might be interesting to have some brains that are independent of others (only if they are connected to io devices) Tuple<int, int>[] brainLinks = Math2D.GetDelaunayTriangulation(brainPositions, chk2DSkipThin.IsChecked.Value, trk2DThinRatio.Value); _voronoi2D = Math2D.GetVoronoi(brainPositions, true); //TODO: If a brain is over saturated, hand some links to a nearby brain //TODO: This method needs to have the logic that spreads out links //TODO: Do some random linkage between neighboring cells Tuple<int, int>[] ioLinks = Worker2D_Simple.LinkBrainsToIO_Voronoi(_voronoi2D, brainPositions, ioPositions); //TODO: Don't just take in points. Need sizes as well #region Draw // Voronoi lines _voronoiLines2D.AddRange(DrawVoronoi(_voronoi2D, _voronoiGrayBrush, 1)); // Brain-Brain links foreach (Tuple<int, int> link in brainLinks) { Point from = _brains2D[link.Item1].Position; Point to = _brains2D[link.Item2].Position; UIElement visual = AddLine(from, to, _brainLinkBrush, 2, true); _linksBrain2D.Add(new Item2D(visual, 0, from, to)); } // Brain-IO links foreach (Tuple<int, int> link in ioLinks) { Point from = _brains2D[link.Item1].Position; Point to = ioPositions[link.Item2]; UIElement visual = AddLine(from, to, _ioLinkBrush, isUnder: true); _linksIO2D.Add(new Item2D(visual, 0, from, to)); } #endregion } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
private Canvas DrawVoronoi(VoronoiResult2D voronoi, Color[] colors, SOMNode[] nodes, ImageInput[][] images, int imageWidth, int imageHeight) { const double MARGINPERCENT = 1.05; #region transform var aabb = Math2D.GetAABB(voronoi.EdgePoints); aabb = Tuple.Create((aabb.Item1.ToVector() * MARGINPERCENT).ToPoint(), (aabb.Item2.ToVector() * MARGINPERCENT).ToPoint()); TransformGroup transform = new TransformGroup(); transform.Children.Add(new TranslateTransform(-aabb.Item1.X, -aabb.Item1.Y)); transform.Children.Add(new ScaleTransform(imageWidth / (aabb.Item2.X - aabb.Item1.X), imageHeight / (aabb.Item2.Y - aabb.Item1.Y))); #endregion Canvas retVal = new Canvas(); for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { #region polygon Polygon polygon = new Polygon(); if (voronoi.EdgesByControlPoint[cntr].Length < 3) { throw new ApplicationException("Expected at least three edge points"); } Edge2D[] edges = voronoi.EdgesByControlPoint[cntr].Select(o => voronoi.Edges[o]).ToArray(); Point[] edgePoints = Edge2D.GetPolygon(edges, 1d); edgePoints = edgePoints. Select(o => transform.Transform(o)). ToArray(); foreach (Point point in edgePoints) { polygon.Points.Add(point); } polygon.Fill = new SolidColorBrush(colors[cntr]); polygon.Stroke = new SolidColorBrush(UtilityWPF.OppositeColor(colors[cntr], false)); polygon.StrokeThickness = 1; polygon.Tag = Tuple.Create(nodes[cntr], images[cntr]); polygon.MouseMove += Polygon_MouseMove_OLD; polygon.MouseLeave += Polygon_MouseLeave_OLD; retVal.Children.Add(polygon); #endregion } return retVal; }
private static Point[][] GetPolygons(VoronoiResult2D voronoi, Vector offset) { Point[][] retVal = new Point[voronoi.ControlPoints.Length][]; for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { retVal[cntr] = voronoi.GetPolygon(cntr, 1). // don't need to worry about ray length, they are all segments Select(o => o + offset). // shifting the points by offset ToArray(); } return retVal; }
private static Tuple<int, int>[] IOLinks_Initial(Set2D[] brains, Item2D[] io, VoronoiResult2D voronoi) { List<Tuple<int, int>> retVal = new List<Tuple<int, int>>(); List<int> remainingIO = Enumerable.Range(0, io.Length).ToList(); // store the remaining so that they can be removed as found (avoid unnecessary IsInside checks) for (int brainCntr = 0; brainCntr < brains.Length; brainCntr++) { Edge2D[] edges = voronoi.EdgesByControlPoint[brainCntr].Select(o => voronoi.Edges[o]).ToArray(); if (edges.Length == 1) { throw new ApplicationException("finish this"); } foreach (int ioIndex in remainingIO.ToArray()) { if (Edge2D.IsInside(edges, io[ioIndex].Position)) { retVal.Add(Tuple.Create(brainCntr, ioIndex)); remainingIO.Remove(ioIndex); } } } return retVal.ToArray(); }
private Item2D[] DrawVoronoi(VoronoiResult2D voronoi, Brush brush, double width = 2) { List<Item2D> retVal = new List<Item2D>(); // This is used to extend rays, ensure they always go off screen double extensionLength = Math.Max(canvas.ActualWidth, canvas.ActualHeight) * 2; foreach (Edge2D edge in voronoi.Edges) { Point from = edge.Point0; Point to = edge.GetPoint1Ext(extensionLength); // if it's a ray, this method will extend it into a segment if (edge.EdgeType == EdgeType.Line) { // Instead of a ray, make a line from = from + (from - to); } UIElement visual = AddLine(from, to, brush, width); retVal.Add(new Item2D(visual, 0, from, to)); } return retVal.ToArray(); }
private void ClearTempVisuals() { _voronoi2D = null; // 2D canvas.Children.RemoveAll(_voronoiLines2D.Select(o => o.Visual)); _voronoiLines2D.Clear(); canvas.Children.RemoveAll(_linksBrain2D.Select(o => o.Visual)); _linksBrain2D.Clear(); canvas.Children.RemoveAll(_linksIO2D.Select(o => o.Visual)); _linksIO2D.Clear(); canvas.Children.RemoveAll(_misc2D.Select(o => o.Visual)); _misc2D.Clear(); // 3D _viewportFull.Children.RemoveAll(_linksBrain3D.Select(o => o.Visual)); _linksBrain3D.Clear(); _viewportFull.Children.RemoveAll(_linksIO3D.Select(o => o.Visual)); _linksIO3D.Clear(); _viewportFull.Children.RemoveAll(_misc3D.Select(o => o.Visual)); _misc3D.Clear(); _viewportFull.Children.RemoveAll(_voronoiBlob3D.Select(o => o.Visual)); _voronoiBlob3D.Clear(); // Stats pnlStats.Children.Clear(); //_voronoi2NeighborData.Clear(); //btn3DVor2D2Save.IsEnabled = false; }
public static Tuple<int, int>[] LinkBrainsToIO_Voronoi(VoronoiResult2D voronoi, Point[] brains, Point[] io) { if (brains.Length == 0) { return new Tuple<int, int>[0]; } else if (brains.Length == 1) { return Enumerable.Range(0, io.Length).Select(o => Tuple.Create(0, o)).ToArray(); } List<Tuple<int, int>> retVal = new List<Tuple<int, int>>(); List<int> remainingIO = Enumerable.Range(0, io.Length).ToList(); // store the remaining so that they can be removed as found (avoid unnecessary IsInside checks) for (int brainCntr = 0; brainCntr < brains.Length; brainCntr++) { Edge2D[] edges = voronoi.EdgesByControlPoint[brainCntr].Select(o => voronoi.Edges[o]).ToArray(); if (edges.Length == 1) { throw new ApplicationException("finish this"); } foreach (int ioIndex in remainingIO.ToArray()) { if (Edge2D.IsInside(edges, io[ioIndex])) { retVal.Add(Tuple.Create(brainCntr, ioIndex)); remainingIO.Remove(ioIndex); } } } return retVal.ToArray(); }
private void btn2DCreateLinksVoronoi_Click(object sender, RoutedEventArgs e) { try { PrepFor2D(); ClearTempVisuals(); if (_brains2D.Count == 0) { return; } var io = UtilityCore.Iterate(_inputs2D, _outputs2D).ToArray(); LinkBrain2D[] brainLinks = null; LinkIO[] ioLinks = null; Worker2D_Voronoi.GetLinks(out brainLinks, out ioLinks, _brains2D.ToArray(), io); Point[] brainSetPoints = Math2D.GetUnique(ioLinks.Select(o => o.Brains.Center)); if (brainSetPoints.Length > 1) { _voronoi2D = Math2D.GetVoronoi(brainSetPoints, true); // this is redundant, since the worker has to get this too, but it's just a tester, and I don't want to complicate the interface } #region Draw // Voronoi lines if (_voronoi2D != null) { _voronoiLines2D.AddRange(DrawVoronoi(_voronoi2D, _voronoiGrayBrush, 1)); } //TODO: Represent the number of links between two items as line thickness // Brain-Brain links if (brainLinks != null) { foreach (var link in brainLinks) { // Group From if (link.Brains1.Items.Length > 1) { _linksBrain2D.Add(DrawBrainGroup(link.Brains1.Positions, link.Brains2.Center)); } // Group To if (link.Brains2.Items.Length > 1) { _linksBrain2D.Add(DrawBrainGroup(link.Brains2.Positions, link.Brains2.Center)); } // Link UIElement visual = AddLine(link.Brains1.Center, link.Brains2.Center, _brainLinkBrush); _linksBrain2D.Add(new Item2D(visual, 0, link.Brains1.Center, link.Brains2.Center)); } } // Brain-IO links if (ioLinks != null) { foreach (var link in ioLinks) { // Group From if (link.Brains.Items.Length > 1) { _linksIO2D.Add(DrawBrainGroup(link.Brains.Positions, link.Brains.Center)); } // Link UIElement visual = AddLine(link.Brains.Center, link.IO.Position, _ioLinkBrush, isUnder: true); _linksIO2D.Add(new Item2D(visual, 0, link.Brains.Center, link.IO.Position)); } } #endregion } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
private static Canvas DrawVoronoi_Blobs(VoronoiResult2D voronoi, Color[] colors, SOMNode[] nodes, ISOMInput[][] inputsByNode, int imageWidth, int imageHeight, BlobEvents events) { const double MARGINPERCENT = 1.05; // Analyze size ratios double[] areas = AnalyzeVoronoiCellSizes(voronoi, inputsByNode); #region transform var aabb = Math2D.GetAABB(voronoi.EdgePoints); aabb = Tuple.Create((aabb.Item1.ToVector() * MARGINPERCENT).ToPoint(), (aabb.Item2.ToVector() * MARGINPERCENT).ToPoint()); TransformGroup transform = new TransformGroup(); transform.Children.Add(new TranslateTransform(-aabb.Item1.X, -aabb.Item1.Y)); transform.Children.Add(new ScaleTransform(imageWidth / (aabb.Item2.X - aabb.Item1.X), imageHeight / (aabb.Item2.Y - aabb.Item1.Y))); #endregion Canvas retVal = new Canvas(); retVal.Effect = new DropShadowEffect() { Color = Colors.Gray, Opacity = .2, BlurRadius = 5, Direction = 0, ShadowDepth = 0, }; for (int cntr = 0; cntr < voronoi.ControlPoints.Length; cntr++) { #region polygon Polygon polygon = new Polygon(); if (voronoi.EdgesByControlPoint[cntr].Length < 3) { throw new ApplicationException("Expected at least three edge points"); } Edge2D[] edges = voronoi.EdgesByControlPoint[cntr].Select(o => voronoi.Edges[o]).ToArray(); Point[] edgePoints = Edge2D.GetPolygon(edges, 1d); // Resize to match the desired area edgePoints = ResizeConvexPolygon(edgePoints, areas[cntr]); // Convert into a smooth blob BezierSegment3D[] bezier = BezierUtil.GetBezierSegments(edgePoints.Select(o => o.ToPoint3D()).ToArray(), .25, true); edgePoints = BezierUtil.GetPath(75, bezier). Select(o => o.ToPoint2D()). ToArray(); // Transform to canvas coords edgePoints = edgePoints. Select(o => transform.Transform(o)). ToArray(); foreach (Point point in edgePoints) { polygon.Points.Add(point); } polygon.Fill = new SolidColorBrush(colors[cntr]); polygon.Stroke = null; // new SolidColorBrush(UtilityWPF.OppositeColor(colors[cntr], false)); polygon.StrokeThickness = 1; polygon.Tag = Tuple.Create(events, nodes[cntr], inputsByNode[cntr]); if (events != null) { if (events.MouseMove != null && events.MouseLeave != null) { polygon.MouseMove += Polygon2D_MouseMove; polygon.MouseLeave += Polygon2D_MouseLeave; } if (events.Click != null) { polygon.MouseUp += Polygon_MouseUp; } } retVal.Children.Add(polygon); #endregion } return retVal; }
private void btn2DVoronoiBrains_Click(object sender, RoutedEventArgs e) { try { PrepFor2D(); ClearTempVisuals(); if (_brains2D.Count == 0) { return; } _voronoi2D = Math2D.GetVoronoi(_brains2D.Select(o => o.Position).ToArray(), true); _voronoiLines2D.AddRange(DrawVoronoi(_voronoi2D, Brushes.Black)); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }