diff --git a/FlowForge.sln.DotSettings.user b/FlowForge.sln.DotSettings.user index 18673f21f63cde82b41f0799297e59fc0290eadc..2ad297b779118bef87198403ab93a69c5330b1f4 100644 --- a/FlowForge.sln.DotSettings.user +++ b/FlowForge.sln.DotSettings.user @@ -4,10 +4,12 @@ <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEdge_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc6dec8134d4e5115e30fcbbde23a657edc52dc4585c5673fe87fae89530f2_003FEdge_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEdge_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff38111ee4ab22cf4c871f13fa7e04fc14b977348d8eae2e69713c39d27b66_003FEdge_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGeometryGraph_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fec51c2d7ba4c960a9dae3716ddab555d654bcbe75d697cc141c3b2c8f247f_003FGeometryGraph_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> + <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGraph_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fade590d7335862ef59866330b1988e328177cd13af84c1df3c6d9bd07195a8c_003FGraph_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIDictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb756d57b94fb4ab9aa95a9b2a97fce1fa24ea0_003Fa1_003F8276683c_003FIDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALayoutHelpers_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd0dd8419a9cbd7bcef7ea0c031796cd8197cb3c658c80b7c71ec2da3918b3_003FLayoutHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F362e998b40631a36346249d25c3c8c712372e68c65f251adc18f8931b4a77a32_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F50b63217dc36f9d6edcabbd75adb3a7f68f1ebd3b4645b30614b43a9eda189_003FNode_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String> + <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F362e998b40631a36346249d25c3c8c712372e68c65f251adc18f8931b4a77a32_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASplineRouter_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fb2961a4f945481bf9a55f7d27e451184c68497a74672874e415414929e5d53a_003FSplineRouter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASugiyamaLayoutSettings_002Ecs_002Fl_003AC_0021_003FUsers_003Ftimon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe49262ac60bbccd8c34311e852def374298e4cf859347b2c83e6a6079f4e7e_003FSugiyamaLayoutSettings_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASugiyamaLayoutSettings_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003Fmp455017_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe49262ac60bbccd8c34311e852def374298e4cf859347b2c83e6a6079f4e7e_003FSugiyamaLayoutSettings_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> \ No newline at end of file diff --git a/MainWindow.xaml b/MainWindow.xaml index 7c214ac2f7ed190b32396245e1dc8a940d6d1b06..6626861622aa6488902dad9412ef097377d9223b 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -1,7 +1,7 @@ <Window x:Class="FlowForge.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="Flow-Forge" Height="600" Width="900"> + Title="Flow-Forge" Height="600" Width="1080"> <Grid x:Name="MainGrid"> <!-- Define two rows: one fixed height for the button and one for the graph viewer --> <Grid.RowDefinitions> @@ -11,7 +11,7 @@ <!-- Button in the first row --> <Button x:Name="InitializeGraphButton" - Content="Initialize Graph" + Content="Initialize graph" Width="120" Height="40" VerticalAlignment="Center" @@ -53,20 +53,38 @@ Margin="460,10,0,10" Grid.Row="0" Click="ExportToLatexButton_Click"/> + + <Button x:Name="SnapToGrid" + Content="Snap to grid" + Width="120" + Height="40" + VerticalAlignment="Center" + HorizontalAlignment="Left" + Margin="610,10,0,10" + Grid.Row="0" + Click="SnapToGridButton_Click"/> <!-- Checkboxes in the first row --> <CheckBox x:Name="IncludeAnimationCheckbox" - Content="Include Animation" + Content="Include animation" VerticalAlignment="Center" HorizontalAlignment="Left" - Margin="620,10,0,10" + Margin="750,-15,0,10" Grid.Row="0"/> <CheckBox x:Name="StandaloneCheckbox" Content="Standalone" VerticalAlignment="Center" HorizontalAlignment="Left" - Margin="770,10,0,10" + Margin="750,30,0,10" + Grid.Row="0" + IsChecked="True"/> + + <CheckBox x:Name="WorstCaseCheckbox" + Content="Force worst case" + VerticalAlignment="Center" + HorizontalAlignment="Left" + Margin="880,-15,0,10" Grid.Row="0" IsChecked="True"/> diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 0df7816a69645ce1b9ce817b3e5c9549519bbf13..5099425a41d3c23e0498d20a84084c030905376b 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -333,5 +333,55 @@ namespace FlowForge TikzCodeGenerator tikzCodeGenerator = new TikzCodeGenerator(_flowGraph, _nodePositions, _fordFulkerson); tikzCodeGenerator.ExportGraphToLatex(IncludeAnimationCheckbox.IsChecked, StandaloneCheckbox.IsChecked); } + + private void SnapToGridButton_Click(object sender, RoutedEventArgs e) + { + if (!_msaglGraph.Nodes.Any()) + { + MessageBox.Show("The graph is not initialized.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // Define grid spacing + const int gridX = 50; // Spacing in the X direction + const int gridY = 50; // Spacing in the Y direction + + // Iterate through each node and snap it to the nearest grid point + foreach (var node in _msaglGraph.Nodes) + { + var position = node.GeometryNode.Center; + + // Calculate the snapped position + double snappedX = Math.Round(position.X / gridX) * gridX; + double snappedY = Math.Round(position.Y / gridY) * gridY; + + // Update the node's position + node.GeometryNode.Center = new Microsoft.Msagl.Core.Geometry.Point(snappedX, snappedY); + + // Reset node attributes to clear selection appearance + node.Attr.Color = MsaglDrawing.Color.Black; // Default color + node.Attr.LineWidth = 1; // Default width + } + + // Update edges to reflect new positions + if (_gViewer != null) + { + _gViewer.Graph = _msaglGraph; + + var sugiyamaSettings = new SugiyamaLayoutSettings(); + sugiyamaSettings.NodeSeparation = 10; + //sugiyamaSettings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.RectilinearToCenter; + sugiyamaSettings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; + sugiyamaSettings.EdgeRoutingSettings.Padding = 1; + sugiyamaSettings.RepetitionCoefficientForOrdering = 100; + sugiyamaSettings.EdgeRoutingSettings.KeepOriginalSpline = false; + + Microsoft.Msagl.Miscellaneous.LayoutHelpers.RouteAndLabelEdges(_msaglGraph.GeometryGraph, + sugiyamaSettings, _msaglGraph.GeometryGraph.Edges, 100, new CancelToken()); + + _gViewer.NeedToCalculateLayout = false; + _gViewer.Graph = _msaglGraph; + } + } } } \ No newline at end of file