private static Brush GetTiledSamples(Point[] edgePoints, ISOMInput[] samples, SOMNode node, int tileWidth, int tileHeight, Action<DrawTileArgs> drawTile) { var dimensions = GetTileImagePositions(samples.Length); // The image tiles will be drawn spiraling out from the center. Order the list so that tiles closest to the node are first (so that // they are drawn closer to the center of the spiral) ISOMInput[] orderedSamples = samples. OrderBy(o => MathND.GetDistanceSquared(o.Weights, node.Weights)). ToArray(); //int tilehalf_left = tileWidth / 2; //int tilehalf_top = tileHeight / 2; //int tilehalf_right = tileWidth - tilehalf_left; //int tilehalf_bot = tileHeight - tilehalf_top; int imageWidth = (dimensions.Item2.X - dimensions.Item1.X + 1) * tileWidth; int imageHeight = (dimensions.Item2.Y - dimensions.Item1.Y + 1) * tileHeight; //int offsetX = (Math.Abs(dimensions.Item1.X) * tileWidth) + tilehalf_left; //int offsetY = (Math.Abs(dimensions.Item1.Y) * tileHeight) + tilehalf_top; //TODO: Get the AABB of edgePoints. If the bitmap will be bigger than the aabb, then draw just enough to totally fill the polygon //NOTE: Copied from UtilityWPF.GetBitmap WriteableBitmap bitmap = new WriteableBitmap(imageWidth, imageHeight, UtilityWPF.DPI, UtilityWPF.DPI, PixelFormats.Pbgra32, null); // may want Bgra32 if performance is an issue int pixelWidth = bitmap.Format.BitsPerPixel / 8; int stride = bitmap.PixelWidth * pixelWidth; // this is the length of one row of pixels byte[] pixels = new byte[bitmap.PixelHeight * stride]; DrawingVisual dv = new DrawingVisual(); using (DrawingContext ctx = dv.RenderOpen()) { for (int cntr = 0; cntr < orderedSamples.Length; cntr++) { int x = (dimensions.Item3[cntr].X - dimensions.Item1.X) * tileWidth; int y = (dimensions.Item3[cntr].Y - dimensions.Item1.Y) * tileWidth; DrawTileArgs args = new DrawTileArgs(orderedSamples[cntr], tileWidth, tileHeight, pixels, x, y, stride, pixelWidth); drawTile(args); } #region DISCARD //int index = 0; //for (int y = 0; y < colorsHeight; y++) //{ // for (int x = 0; x < colorsWidth; x++) // { // int gray = (grayColors[index] * grayValueScale).ToInt_Round(); // if (gray < 0) gray = 0; // if (gray > 255) gray = 255; // byte grayByte = Convert.ToByte(gray); // Color color = Color.FromRgb(grayByte, grayByte, grayByte); // ctx.DrawRectangle(new SolidColorBrush(color), null, new Rect(x * scaleX, y * scaleY, scaleX, scaleY)); // index++; // } //} #endregion } bitmap.WritePixels(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight), pixels, stride, 0); return new ImageBrush(bitmap) { Stretch = Stretch.None, }; }
/// <summary> /// This is a helper method to turn som node positions into points to pass to AddStaticItems() /// </summary> public static IEnumerable<Tuple<ISOMInput, Point3D>> GetSOMNodeStaticPositions(SOMNode node, SOMNode[] allNodes, double innerRadius) { // Convert to Point3D var initial = allNodes. Select(o => { Vector3D position = new Vector3D(); if (o.Position.Length >= 1) position.X = o.Position[0]; if (o.Position.Length >= 2) position.Y = o.Position[1]; if (o.Position.Length >= 3) position.Z = o.Position[2]; return Tuple.Create(o, position, position.Length); }). OrderBy(o => o.Item3). ToArray(); // Find the closest one (that isn't the one passed in) var firstNonZero = initial. Where(o => o.Item1.Token != node.Token). FirstOrDefault(o => !o.Item3.IsNearZero()); double scale = 1d; if (firstNonZero != null) { scale = (innerRadius * 1.25) / firstNonZero.Item3; } // Make sure they are spaced properly var scaled = initial. Select(o => Tuple.Create(o.Item1, (o.Item2 * scale).ToPoint())). ToArray(); // These need to be centered over the origin, because the points will try to drift to the center Point3D center = Math3D.GetCenter(scaled.Select(o => o.Item2)); Vector3D offset = new Vector3D(-center.X, -center.Y, -center.Z); return scaled. Select(o => Tuple.Create((ISOMInput)o.Item1, o.Item2 + offset)). ToArray(); }
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 void Polygon_Click(Polygon poly, SOMNode node, ISOMInput[] inputs, MouseEventArgs e) { try { int index = _result.Nodes.IndexOf(node, (o, p) => o.Token == p.Token); DBRowsDetail viewer = new DBRowsDetail(_queryResults, _columns, _result, index) { Background = poly.Fill, }; viewer.Closed += DBRowsDetail_Closed; _childWindows.Add(viewer); viewer.Show(); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
public static Color GetNodeColor(SOMNode node) { var raw = GetNodeColor_RGB(node.Weights); return GetNodeColor_Finish(raw); }
public OverlayPolygonStats(SOMNode node, ISOMInput[] images, Rect canvasAABB, Vector cursorOffset, Canvas overlay) { this.Node = node; this.Images = images; this.CanvasAABB = canvasAABB; this.CursorOffset = cursorOffset; this.Overlay = overlay; }
private void Polygon_MouseMove(Polygon poly, SOMNode node, ISOMInput[] inputs, MouseEventArgs e) { try { if (_overlayPolyStats == null || _overlayPolyStats.Node.Token != node.Token) { BuildOverlay2D(node, inputs, true, true); } Point mousePos = e.GetPosition(panelDisplay); double left = mousePos.X + _overlayPolyStats.CanvasAABB.Left + _overlayPolyStats.CursorOffset.X - 1; //double top = mousePos.Y + _overlayPolyStats.CanvasAABB.Top + _overlayPolyStats.CursorOffset.Y - 1; //double top = mousePos.Y + _overlayPolyStats.CanvasAABB.Top - _overlayPolyStats.CursorOffset.Y - 1; double top = mousePos.Y + _overlayPolyStats.CanvasAABB.Top - 1; // Y is already centered Canvas.SetLeft(_overlayPolyStats.Overlay, left); Canvas.SetTop(_overlayPolyStats.Overlay, top); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
private void BuildOverlay2D(SOMNode node, ISOMInput[] inputs, bool showCount = false, bool showNodeHash = false) { const double SMALLFONT1 = 17; const double LARGEFONT1 = 21; const double SMALLFONT2 = 15; const double LARGEFONT2 = 18; const double SMALLFONT3 = 12; const double LARGEFONT3 = 14; const double SMALLLINE1 = .8; const double LARGELINE1 = 1; const double SMALLLINE2 = .5; const double LARGELINE2 = .85; const double SMALLLINE3 = .3; const double LARGELINE3 = .7; Canvas canvas = new Canvas(); List<Rect> rectangles = new List<Rect>(); #region cursor rectangle var cursorRect = SelfOrganizingMapsWPF.GetMouseCursorRect(); rectangles.Add(cursorRect.Item1); // This is just for debugging //Rectangle cursorVisual = new Rectangle() //{ // Width = cursorRect.Item1.Width, // Height = cursorRect.Item1.Height, // Fill = new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192, 255)), //}; //Canvas.SetLeft(cursorVisual, cursorRect.Item1.Left); //Canvas.SetTop(cursorVisual, cursorRect.Item1.Top); //canvas.Children.Add(cursorVisual); #endregion #region count text if (showCount && _result != null && _result.InputsByNode != null) // it's possible that they are changing things while old graphics are still showing { StackPanel textPanel = new StackPanel() { Orientation = Orientation.Horizontal, }; // "rows " OutlinedTextBlock text = SelfOrganizingMapsWPF.GetOutlineText("rows ", SMALLFONT1, SMALLLINE1); text.Margin = new Thickness(0, 0, 4, 0); textPanel.Children.Add(text); // percent double percent = -1; if (_result.InputsByNode.Length == 0) { if (inputs.Length == 0) { percent = 0; } else { percent = -1; } } else { percent = inputs.Length.ToDouble() / _result.InputsByNode.SelectMany(o => o).Count().ToDouble(); percent *= 100d; } text = SelfOrganizingMapsWPF.GetOutlineText(percent.ToStringSignificantDigits(2) + "%", LARGEFONT1, LARGELINE1); textPanel.Children.Add(text); // Place on canvas textPanel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); // aparently, the infinity is important to get an accurate desired size Size textSize = textPanel.DesiredSize; Rect textRect = SelfOrganizingMapsWPF.GetFreeSpot(textSize, new Point(0, 0), new Vector(0, -1), rectangles); rectangles.Add(textRect); Canvas.SetLeft(textPanel, textRect.Left); Canvas.SetTop(textPanel, textRect.Top); canvas.Children.Add(textPanel); } #endregion double[] nodeCenter = inputs.Length == 0 ? node.Weights : MathND.GetCenter(inputs.Select(o => o.Weights)); #region node hash if (showNodeHash) { var nodeCtrl = GetVectorVisual(node.Weights); // Place on canvas Rect nodeRect = SelfOrganizingMapsWPF.GetFreeSpot(new Size(nodeCtrl.Item2.X, nodeCtrl.Item2.Y), new Point(0, 0), new Vector(0, -1), rectangles); rectangles.Add(nodeRect); Canvas.SetLeft(nodeCtrl.Item1, nodeRect.Left); Canvas.SetTop(nodeCtrl.Item1, nodeRect.Top); canvas.Children.Add(nodeCtrl.Item1); } #endregion //TODO: For the first attempt, put all row descriptions under #region rows if (_queryResults != null && _queryResults.Results != null) { var rowsCtrl = GetRowsVisual(_queryResults.ColumnNames, inputs, _detailsHeaderStyle, _detailsBodyStyle); // Place on canvas Rect rowsRect = SelfOrganizingMapsWPF.GetFreeSpot(new Size(rowsCtrl.Item2.X, rowsCtrl.Item2.Y), new Point(0, 0), new Vector(0, 1), rectangles); rectangles.Add(rowsRect); Canvas.SetLeft(rowsCtrl.Item1, rowsRect.Left); Canvas.SetTop(rowsCtrl.Item1, rowsRect.Top); canvas.Children.Add(rowsCtrl.Item1); } #endregion Rect canvasAABB = Math2D.GetAABB(rectangles); //NOTE: All the items are placed around zero zero, but that may not be half width and height (items may not be centered) canvas.RenderTransform = new TranslateTransform(-canvasAABB.Left, -canvasAABB.Top); panelOverlay.Children.Clear(); panelOverlay.Children.Add(canvas); _overlayPolyStats = new OverlayPolygonStats(node, inputs, canvasAABB, cursorRect.Item2, canvas); }
private void Polygon_Click(Polygon sender, SOMNode node, ISOMInput[] images, MouseEventArgs e) { try { Color nodeColor = UtilityWPF.ExtractColor(sender.Fill); RadialGradientBrush brush = new RadialGradientBrush(); brush.GradientStops.Add(new GradientStop(UtilityWPF.AlphaBlend(Colors.White, nodeColor, .8), 0)); brush.GradientStops.Add(new GradientStop(UtilityWPF.AlphaBlend(Colors.White, nodeColor, .58), 1.9)); HighDimensionVisualizer visualizer = new HighDimensionVisualizer(GetPreviewImage, SelfOrganizingMapsWPF.GetNodeColor, chkVisualizerStaticDots.IsChecked.Value, chkVisualizer3D.IsChecked.Value); visualizer.AddStaticItems(HighDimensionVisualizer.GetSOMNodeStaticPositions(node, _nodes, HighDimensionVisualizer.RADIUS)); visualizer.AddItems(images); Window window = new Window() { Width = 400, Height = 400, Title = this.Title + " " + images.Length.ToString(), Background = brush, ResizeMode = ResizeMode.CanResizeWithGrip, Content = visualizer, Owner = this, // keep it on top of this window }; window.Show(); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
public SOMNodeVoronoiCell(int index, SOMNode node, int[] neighbors, double size, double sizePercentOfTotal) { this.Index = index; this.Node = node; this.Neighbors = neighbors; this.Size = size; this.SizePercentOfTotal = sizePercentOfTotal; }
private void BuildOverlay2D(SOMNode node, ISOMInput[] images, bool showCount, bool showNodeHash, bool showImageHash, bool showSpread, bool showPerImageDistance) { const int IMAGESIZE = 80; const int NODEHASHSIZE = 100; const double SMALLFONT1 = 17; const double LARGEFONT1 = 21; const double SMALLFONT2 = 15; const double LARGEFONT2 = 18; const double SMALLFONT3 = 12; const double LARGEFONT3 = 14; const double SMALLLINE1 = .8; const double LARGELINE1 = 1; const double SMALLLINE2 = .5; const double LARGELINE2 = .85; const double SMALLLINE3 = .3; const double LARGELINE3 = .7; Canvas canvas = new Canvas(); List<Rect> rectangles = new List<Rect>(); #region cursor rectangle var cursorRect = SelfOrganizingMapsWPF.GetMouseCursorRect(0); rectangles.Add(cursorRect.Item1); // This is just for debugging //Rectangle cursorVisual = new Rectangle() //{ // Width = cursorRect.Item1.Width, // Height = cursorRect.Item1.Height, // Fill = new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192, 255)), //}; //Canvas.SetLeft(cursorVisual, cursorRect.Item1.Left); //Canvas.SetTop(cursorVisual, cursorRect.Item1.Top); //canvas.Children.Add(cursorVisual); #endregion #region count text if (showCount) { StackPanel textPanel = new StackPanel() { Orientation = Orientation.Horizontal, }; // "images " OutlinedTextBlock text = SelfOrganizingMapsWPF.GetOutlineText("images ", SMALLFONT1, SMALLLINE1); text.Margin = new Thickness(0, 0, 4, 0); textPanel.Children.Add(text); // count text = SelfOrganizingMapsWPF.GetOutlineText(images.Length.ToString("N0"), LARGEFONT1, LARGELINE1); textPanel.Children.Add(text); // Place on canvas textPanel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); // aparently, the infinity is important to get an accurate desired size Size textSize = textPanel.DesiredSize; Rect textRect = SelfOrganizingMapsWPF.GetFreeSpot(textSize, new Point(0, 0), new Vector(0, 1), rectangles); rectangles.Add(textRect); Canvas.SetLeft(textPanel, textRect.Left); Canvas.SetTop(textPanel, textRect.Top); canvas.Children.Add(textPanel); } #endregion #region spread var nodeImages = images.Select(o => o.Weights); var allImages = _imagesByNode.SelectMany(o => o).Select(o => o.Weights); double nodeSpread = images.Length == 0 ? 0d : SelfOrganizingMaps.GetTotalSpread(nodeImages); double totalSpread = SelfOrganizingMaps.GetTotalSpread(allImages); if (showSpread && images.Length > 0) { double nodeStandDev = MathND.GetStandardDeviation(nodeImages); double totalStandDev = MathND.GetStandardDeviation(allImages); double percentSpread = nodeSpread / totalSpread; double pecentStandDev = nodeStandDev / totalSpread; Grid spreadPanel = new Grid() { Margin = new Thickness(2), }; spreadPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); spreadPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(4) }); spreadPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(2) }); spreadPanel.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); AddTextRow(spreadPanel, 0, "node stand dev", (pecentStandDev * 100).ToStringSignificantDigits(2) + "%", SMALLFONT2, LARGEFONT2, SMALLLINE2, LARGELINE2, true); AddTextRow(spreadPanel, 2, "node spread", (percentSpread * 100).ToStringSignificantDigits(2) + "%", SMALLFONT2, LARGEFONT2, SMALLLINE2, LARGELINE2, false); AddTextRow(spreadPanel, 4, "node stand dev", nodeStandDev.ToStringSignificantDigits(2), SMALLFONT3, LARGEFONT3, SMALLLINE3, LARGELINE3, true); AddTextRow(spreadPanel, 6, "node spread", nodeSpread.ToStringSignificantDigits(2), SMALLFONT3, LARGEFONT3, SMALLLINE3, LARGELINE3, false); AddTextRow(spreadPanel, 8, "total stand dev", totalStandDev.ToStringSignificantDigits(2), SMALLFONT3, LARGEFONT3, SMALLLINE3, LARGELINE3, true); AddTextRow(spreadPanel, 10, "total spread", totalSpread.ToStringSignificantDigits(2), SMALLFONT3, LARGEFONT3, SMALLLINE3, LARGELINE3, false); // Place on canvas spreadPanel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); // aparently, the infinity is important to get an accurate desired size Size spreadSize = spreadPanel.DesiredSize; Rect spreadRect = SelfOrganizingMapsWPF.GetFreeSpot(spreadSize, new Point(0, 0), new Vector(0, 1), rectangles); rectangles.Add(spreadRect); Canvas.SetLeft(spreadPanel, spreadRect.Left); Canvas.SetTop(spreadPanel, spreadRect.Top); canvas.Children.Add(spreadPanel); } #endregion double[] nodeCenter = images.Length == 0 ? node.Weights : MathND.GetCenter(nodeImages); #region node hash if (showNodeHash) { ImageInput nodeImage = new ImageInput(null, node.Weights, node.Weights); double nodeDist = MathND.GetDistance(nodeImage.Weights, nodeCenter); double nodeDistPercent = nodeSpread.IsNearZero() ? 1d : (nodeDist / nodeSpread); // if zero or one node, then spread will be zero Tuple<UIElement, VectorInt> nodeCtrl = GetPreviewImage(nodeImage, true, NODEHASHSIZE, showPerImageDistance, nodeDistPercent); // Place on canvas Rect nodeRect = SelfOrganizingMapsWPF.GetFreeSpot(new Size(nodeCtrl.Item2.X, nodeCtrl.Item2.Y), new Point(0, 0), new Vector(0, -1), rectangles); rectangles.Add(nodeRect); Canvas.SetLeft(nodeCtrl.Item1, nodeRect.Left); Canvas.SetTop(nodeCtrl.Item1, nodeRect.Top); canvas.Children.Add(nodeCtrl.Item1); } #endregion #region images foreach (ImageInput image in images) { double imageDistPercent; if (images.Length == 1) { imageDistPercent = 1; } else { imageDistPercent = MathND.GetDistance(image.Weights, nodeCenter) / nodeSpread; } // Create the image (and any other graphics for that image) Tuple<UIElement, VectorInt> imageCtrl = GetPreviewImage(image, showImageHash, IMAGESIZE, showPerImageDistance, imageDistPercent); // Find a spot for it var imageRect = Enumerable.Range(0, 10). Select(o => { Vector direction = Math3D.GetRandomVector_Circular_Shell(1).ToVector2D(); Rect imageRect2 = SelfOrganizingMapsWPF.GetFreeSpot(new Size(imageCtrl.Item2.X, imageCtrl.Item2.Y), new Point(0, 0), direction, rectangles); return new { Rect = imageRect2, Distance = new Vector(imageRect2.CenterX(), imageRect2.CenterY()).LengthSquared }; }). OrderBy(o => o.Distance). First(). Rect; Canvas.SetLeft(imageCtrl.Item1, imageRect.Left); Canvas.SetTop(imageCtrl.Item1, imageRect.Top); // Add it rectangles.Add(imageRect); canvas.Children.Add(imageCtrl.Item1); } #endregion Rect canvasAABB = Math2D.GetAABB(rectangles); //NOTE: All the items are placed around zero zero, but that may not be half width and height (items may not be centered) canvas.RenderTransform = new TranslateTransform(-canvasAABB.Left, -canvasAABB.Top); panelOverlay.Children.Clear(); panelOverlay.Children.Add(canvas); _overlayPolyStats = new OverlayPolygonStats(node, images, canvasAABB, cursorRect.Item2, canvas); }
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; }