public Rect GetIconRect(int gridSize) { if (_iconRect == default || _gridSizeIconRect != gridSize) { var objRect = CalculateScreenRect(gridSize); if (_lastScreenRectForIcon != objRect) { // draw icon 2x2 grid cells large var minSize = Math.Min(Size.Width, Size.Height); //minSize = minSize == 1 ? minSize : Math.Floor(NthRoot(minSize, Constants.IconSizeFactor) + 1); var iconSize = _coordinateHelper.GridToScreen(new Size(minSize, minSize), gridSize); iconSize = minSize == 1 ? iconSize : new Size(MathHelper.NthRoot(iconSize.Width, Constants.IconSizeFactor), MathHelper.NthRoot(iconSize.Height, Constants.IconSizeFactor)); // center icon within the object var iconPos = objRect.TopLeft; iconPos.X += (objRect.Width / 2) - (iconSize.Width / 2); iconPos.Y += (objRect.Height / 2) - (iconSize.Height / 2); _iconRect = new Rect(iconPos, iconSize); _gridSizeIconRect = gridSize; _lastScreenRectForIcon = objRect; } } return(_iconRect); }
/// <summary> /// Asynchronously renders the current layout to file. /// </summary> /// <param name="filename">filename of the output image</param> /// <param name="border">normalization value used prior to exporting</param> /// <param name="exportZoom">indicates whether the current zoom level should be applied, if false the default zoom is used</param> /// <param name="exportSelection">indicates whether selection and influence highlights should be rendered</param> private void RenderToFile(string filename, int border, bool exportZoom, bool exportSelection, bool renderStatistics) { if (annoCanvas.PlacedObjects.Count == 0) { return; } // copy all objects var allObjects = annoCanvas.PlacedObjects.Select(_ => new AnnoObject(_)).Cast <AnnoObject>().ToList(); // copy selected objects // note: should be references to the correct copied objects from allObjects var selectedObjects = annoCanvas.SelectedObjects.Select(_ => new AnnoObject(_)).ToList(); Debug.WriteLine($"UI thread: {Thread.CurrentThread.ManagedThreadId} ({Thread.CurrentThread.Name})"); void renderThread() { Debug.WriteLine($"Render thread: {Thread.CurrentThread.ManagedThreadId} ({Thread.CurrentThread.Name})"); Stopwatch sw = new Stopwatch(); sw.Start(); var icons = new Dictionary <string, IconImage>(StringComparer.OrdinalIgnoreCase); foreach (var curIcon in annoCanvas.Icons) { icons.Add(curIcon.Key, new IconImage(curIcon.Value.Name, curIcon.Value.Localizations, curIcon.Value.IconPath)); } // initialize output canvas var target = new AnnoCanvas(annoCanvas.BuildingPresets, icons) { PlacedObjects = allObjects, RenderGrid = annoCanvas.RenderGrid, RenderIcon = annoCanvas.RenderIcon, RenderLabel = annoCanvas.RenderLabel }; sw.Stop(); Debug.WriteLine($"creating canvas took: {sw.ElapsedMilliseconds}ms"); // normalize layout target.Normalize(border); // set zoom level if (exportZoom) { target.GridSize = annoCanvas.GridSize; } // set selection if (exportSelection) { target.SelectedObjects.AddRange(selectedObjects); } // calculate output size var width = _coordinateHelper.GridToScreen(target.PlacedObjects.Max(_ => _.Position.X + _.Size.Width) + border, target.GridSize); //if +1 then there are weird black lines next to the statistics view var height = _coordinateHelper.GridToScreen(target.PlacedObjects.Max(_ => _.Position.Y + _.Size.Height) + border, target.GridSize) + 1; //+1 for black grid line at bottom if (renderStatistics) { var exportStatisticsView = new StatisticsView { Margin = new Thickness(5, 0, 0, 0) }; exportStatisticsView.statisticsViewModel.UpdateStatistics(target.PlacedObjects, target.SelectedObjects, target.BuildingPresets); exportStatisticsView.statisticsViewModel.CopyLocalization(_mainViewModel.StatisticsViewModel); exportStatisticsView.statisticsViewModel.ShowBuildingList = _mainViewModel.StatisticsViewModel.ShowBuildingList; target.StatisticsPanel.Children.Add(exportStatisticsView); //according to https://stackoverflow.com/a/25507450 // and https://stackoverflow.com/a/1320666 exportStatisticsView.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); //exportStatisticsView.Arrange(new Rect(new Point(0, 0), exportStatisticsView.DesiredSize)); if (exportStatisticsView.DesiredSize.Height > height) { height = exportStatisticsView.DesiredSize.Height + target.LinePenThickness + border; } width += exportStatisticsView.DesiredSize.Width + target.LinePenThickness; } target.Width = width; target.Height = height; target.UpdateLayout(); // apply size var outputSize = new Size(width, height); target.Measure(outputSize); target.Arrange(new Rect(outputSize)); // render canvas to file DataIO.RenderToFile(target, filename); } var thread = new Thread(renderThread); thread.IsBackground = true; thread.Name = "exportImage"; thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(TimeSpan.FromSeconds(10)); }