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