From 288b969314e72acaa7f32053592fd56b987751a9 Mon Sep 17 00:00:00 2001
From: Paul-Winpenny <92634321+Paul-Winpenny@users.noreply.github.com>
Date: Thu, 31 Oct 2024 16:30:27 +0000
Subject: [PATCH] The graphs actually look quite clean right now, the scaling
 aspect will need to be made independent from the other axis (e.g. shrinking
 the horizontal shoulnd't affect the length of the graph, just the width).

---
 App/RobobinApp/App.xaml.cs                    |   9 ++
 App/RobobinApp/Models/Graph.cs                |  10 +-
 .../ViewModels/MainPageViewModel.cs           | 120 +++++++++++++++---
 App/RobobinApp/Views/CentreGraph.xaml.cs      |  63 ++++++---
 App/RobobinApp/Views/MainPage.xaml            |  11 +-
 App/RobobinApp/Views/MainPage.xaml.cs         |  22 +++-
 6 files changed, 197 insertions(+), 38 deletions(-)

diff --git a/App/RobobinApp/App.xaml.cs b/App/RobobinApp/App.xaml.cs
index 5f31488a..848550bd 100644
--- a/App/RobobinApp/App.xaml.cs
+++ b/App/RobobinApp/App.xaml.cs
@@ -19,7 +19,16 @@ public partial class App : Application
 
         MainPage = new AppShell();
     }
+    protected override Window CreateWindow(IActivationState activationState)
+    {
+        var window = base.CreateWindow(activationState);
+
 
+        window.MinimumWidth = 800; 
+        window.MinimumHeight = 650; 
+
+        return window;
+    }
     private void ConfigureLogging()
     {
         var loggerFactory = LoggerFactory.Create(builder =>
diff --git a/App/RobobinApp/Models/Graph.cs b/App/RobobinApp/Models/Graph.cs
index 414492e4..e8fa370c 100644
--- a/App/RobobinApp/Models/Graph.cs
+++ b/App/RobobinApp/Models/Graph.cs
@@ -22,11 +22,19 @@ namespace Robobin.Models
 
     public class Graph
     {
+        public string Name { get; set; }
         public List<Node> Nodes { get; set; }
         public (float magnitude, float angle)[,] AdjacencyMatrix { get; set; }
 
-        public Graph(List<Node> nodes, (float, float)[,] adjacencyMatrix)
+        public Graph(string name, List<Node> nodes, (float, float)[,] adjacencyMatrix)
+        {
+            Name = name;
+            Nodes = nodes;
+            AdjacencyMatrix = adjacencyMatrix;
+        }
+        public Graph( List<Node> nodes, (float, float)[,] adjacencyMatrix)
         {
+            Name = "Graph";
             Nodes = nodes;
             AdjacencyMatrix = adjacencyMatrix;
         }
diff --git a/App/RobobinApp/ViewModels/MainPageViewModel.cs b/App/RobobinApp/ViewModels/MainPageViewModel.cs
index 2841d931..5d1041cb 100644
--- a/App/RobobinApp/ViewModels/MainPageViewModel.cs
+++ b/App/RobobinApp/ViewModels/MainPageViewModel.cs
@@ -1,3 +1,4 @@
+using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Runtime.CompilerServices;
 using System.Windows.Input;
@@ -14,31 +15,120 @@ namespace RobobinApp.ViewModels
     {
         private bool _isBusy;
         private string _statusMessage;
-        public Graph Graph { get; private set; }
+
         public ICommand ConnectToRobobinCommand { get; }
 
+        private Graph _selectedGraph;
+        public ObservableCollection<Graph> Graphs { get; }
+        public ICommand SelectGraphCommand { get; }
+        public Graph Graph
+        {
+            get => _selectedGraph;
+            set
+            {
+                _selectedGraph = value;
+                OnPropertyChanged();
+            }
+        }
+        public ObservableCollection<string> GraphNames { get; }
+
         public MainPageViewModel()
         {
             ConnectToRobobinCommand = new Command(async () => await OnConnectToRobobin());
+            SelectGraphCommand = new Command<int>(OnSelectGraph);
 
-            // Create nodes with X and Y coordinates
-            var nodes = new List<Node>
+            var graphNodes1 = new List<Node>
+{
+    new Node("A", 50, 50),
+    new Node("B", 150, 50),
+    new Node("C", 250, 50),
+    new Node("Home", 350, 50),
+    new Node("E", 50, 150),
+    new Node("F", 150, 150),
+    new Node("G", 250, 150),
+    new Node("H", 350, 150),
+    new Node("I", 50, 250),
+    new Node("J", 150, 250),
+    new Node("K", 250, 250),
+    new Node("L", 350, 250),
+    new Node("M", 50, 350),
+    new Node("N", 150, 350),
+    new Node("O", 350, 350)
+};
+
+            var graphMatrix1 = CalculatePolarConnections(graphNodes1, new bool[,]
             {
-                new Node("N1", 100, 100), // Example coordinates
-                new Node("N2", 200, 100),
-                new Node("N3", 150, 200),
-            };
+    { false, true, false, false, true, false, false, false, false, false, false, false, false, false, false },
+    { true, false, true, false, false, true, false, false, false, false, false, false, false, false, false },
+    { false, true, false, true, false, false, true, false, false, false, false, false, false, false, false },
+    { false, false, true, false, false, false, false, true, false, false, false, false, false, false, true },
+    { true, false, false, false, false, true, false, false, true, false, false, false, false, false, false },
+    { false, true, false, false, true, false, true, false, false, true, false, false, false, false, false },
+    { false, false, true, false, false, true, false, true, false, false, true, false, false, false, false },
+    { false, false, false, true, false, false, true, false, false, false, false, true, false, false, false },
+    { false, false, false, false, true, false, false, false, false, true, false, false, true, false, false },
+    { false, false, false, false, false, true, false, false, true, false, true, false, false, true, false },
+    { false, false, false, false, false, false, true, false, false, true, false, true, false, false, false },
+    { false, false, false, false, false, false, false, true, false, false, true, false, false, false, true },
+    { false, false, false, false, false, false, false, false, true, false, false, false, false, true, false },
+    { false, false, false, false, false, false, false, false, false, true, false, false, true, false, true },
+    { false, false, false, true, false, false, false, false, false, false, false, true, false, true, false }
+            });
+
+            var graph1 = new Graph("Lab 1", graphNodes1, graphMatrix1);
+
+
+
+
+
 
-            // Create an empty adjacency matrix for three nodes
-            var adjacencyMatrix = new (float, float)[,]
+
+
+
+            var graph2Nodes = new List<Node>
+            {
+                new Node("Home", 50, 50),
+                new Node("B", 250, 50),
+                new Node("C", 150, 150),
+                new Node("D", 150, 300)
+            };
+            var graph2Matrix = CalculatePolarConnections(graph2Nodes, new bool[,]
+            {
+                { false, true, true, false },
+                { true, false, true, true },
+                { true, true, false, true },
+                { false, true, true, false }
+            });
+            var graph2 = new Graph("Lab 2",graph2Nodes, graph2Matrix);
+
+            var graph3Nodes = new List<Node>
+            {
+                new Node("X", 75, 75),
+                new Node("Home", 300, 75),
+                new Node("Z", 200, 250)
+            };
+            var graph3Matrix = CalculatePolarConnections(graph3Nodes, new bool[,]
             {
-                { (0, 0),            (100, 0),         (111.80f, 63.44f) },
-                { (100, 180),        (0, 0),           (111.80f, 116.57f) },
-                { (111.80f, -116.56f), (111.80f, -63.43f), (0, 0) }
-               };
+                { false, true, true },
+                { true, false, true },
+                { true, true, false }
+            });
+            var graph3 = new Graph("Lab3", graph3Nodes, graph3Matrix);
 
-            // Create graph
-            Graph = new Graph(nodes, adjacencyMatrix);
+
+
+            // Add graphs to collection
+            Graphs = new ObservableCollection<Graph> { graph1, graph2, graph3 };
+            GraphNames = new ObservableCollection<string>(Graphs.Select(g => g.Name)); // Create list of names
+            Graph = Graphs.First();
+        }
+
+        private void OnSelectGraph(int graphIndex)
+        {
+            if (graphIndex >= 0 && graphIndex < Graphs.Count)
+            {
+                Graph = Graphs[graphIndex];
+            }
         }
         public static (float magnitude, float angle)[,] CalculatePolarConnections(List<Node> nodes, bool[,] connections)
         {
diff --git a/App/RobobinApp/Views/CentreGraph.xaml.cs b/App/RobobinApp/Views/CentreGraph.xaml.cs
index 53a9a02c..6c2d591e 100644
--- a/App/RobobinApp/Views/CentreGraph.xaml.cs
+++ b/App/RobobinApp/Views/CentreGraph.xaml.cs
@@ -8,7 +8,6 @@ namespace RobobinApp.Views
     {
         private Graph _graph;
 
-        // Method to set the graph data
         public void SetGraph(Graph graph)
         {
             _graph = graph;
@@ -18,39 +17,67 @@ namespace RobobinApp.Views
         {
             if (_graph == null) return;
 
-            // Set the background color
-            canvas.FillColor = Colors.LightPink;
+      
+            canvas.FillColor = Color.FromHex("#2C2F33");
             canvas.FillRectangle(dirtyRect);
 
-            // Draw nodes and edges
-            const float nodeRadius = 10; // Radius for nodes
+       
+            float minX = _graph.Nodes.Min(node => node.X);
+            float minY = _graph.Nodes.Min(node => node.Y);
+            float maxX = _graph.Nodes.Max(node => node.X);
+            float maxY = _graph.Nodes.Max(node => node.Y);
+
+            float graphWidth = maxX - minX;
+            float graphHeight = maxY - minY;
+
+            float scaleX = dirtyRect.Width / graphWidth;
+            float scaleY = dirtyRect.Height / graphHeight;
+            float scale = Math.Min(scaleX, scaleY) * 0.8f; 
+
+            float offsetX = dirtyRect.Center.X - ((minX + maxX) * 0.5f) * scale;
+            float offsetY = dirtyRect.Center.Y - ((minY + maxY) * 0.5f) * scale;
+
+     
+            const float baseNodeRadius = 5;
+            float nodeRadius = baseNodeRadius * scale;
 
             foreach (var node in _graph.Nodes)
             {
-                // Draw the node
-                canvas.FillColor = Colors.Red;
-                canvas.FillCircle(node.X, node.Y, nodeRadius);
-                canvas.DrawString(node.Name, node.X + 12, node.Y - 5, HorizontalAlignment.Left);
-
-                // Draw edges based on the adjacency matrix
                 for (int j = 0; j < _graph.Nodes.Count; j++)
                 {
                     var (magnitude, angle) = _graph.AdjacencyMatrix[_graph.Nodes.IndexOf(node), j];
 
-                    // Only draw if there's a valid connection (magnitude > 0)
                     if (magnitude > 0)
                     {
-                        // Calculate the target node's coordinates based on the angle and magnitude
-                        float targetX = node.X + magnitude * MathF.Cos(MathF.PI * (angle / 180));
-                        float targetY = node.Y + magnitude * MathF.Sin(MathF.PI * (angle / 180));
 
-                        // Draw edge
-                        canvas.StrokeColor = Colors.Black;
+                        float targetX = (node.X + magnitude * MathF.Cos(MathF.PI * angle / 180)) * scale + offsetX;
+                        float targetY = (node.Y + magnitude * MathF.Sin(MathF.PI * angle / 180)) * scale + offsetY;
+
+      
+                        canvas.StrokeColor = Colors.Grey;
                         canvas.StrokeSize = 2;
-                        canvas.DrawLine(node.X, node.Y, targetX, targetY); // Draw edge
+                        canvas.DrawLine(node.X * scale + offsetX, node.Y * scale + offsetY, targetX, targetY);
                     }
                 }
             }
+
+            // Draw nodes
+            foreach (var node in _graph.Nodes)
+            {
+                float scaledX = node.X * scale + offsetX;
+                float scaledY = node.Y * scale + offsetY;
+                canvas.FillColor = Colors.Red;
+
+                if (node.Name == "Home")
+                {
+                    canvas.FillColor = Colors.Green;
+
+                }
+                canvas.FillCircle(scaledX, scaledY, nodeRadius);
+                canvas.FontColor = Colors.White;
+                canvas.DrawString(node.Name, scaledX + nodeRadius + 2, scaledY - nodeRadius, HorizontalAlignment.Left);
+            }
         }
+
     }
 }
diff --git a/App/RobobinApp/Views/MainPage.xaml b/App/RobobinApp/Views/MainPage.xaml
index d771d9da..bd416ccc 100644
--- a/App/RobobinApp/Views/MainPage.xaml
+++ b/App/RobobinApp/Views/MainPage.xaml
@@ -44,9 +44,8 @@
                HorizontalOptions="FillAndExpand" 
                VerticalOptions="FillAndExpand"
                Grid.Column="1" Grid.Row="0">
-            <GraphicsView Drawable="{StaticResource drawable}"
-                          HeightRequest="300"
-                          WidthRequest="400" />
+            <GraphicsView x:Name="GraphicsView"
+                  Drawable="{StaticResource drawable}" />
         </Frame>
 
         <VerticalStackLayout StyleClass="sideFrame" 
@@ -55,6 +54,12 @@
                              Grid.Column="2" Grid.Row="0">
             <HorizontalStackLayout HorizontalOptions="Start" VerticalOptions="End">
                 <Button Text="Info" />
+                 <Picker Title="Select Graph" 
+                ItemsSource="{Binding GraphNames}"
+                SelectedIndexChanged="OnGraphSelected"
+                HorizontalOptions="Center" />
+
+
             </HorizontalStackLayout>
             <local:SideBox HeaderTitle="Mode:" />
             <local:SideBox HeaderTitle="Admin:" />
diff --git a/App/RobobinApp/Views/MainPage.xaml.cs b/App/RobobinApp/Views/MainPage.xaml.cs
index 6a20095e..886ab3f3 100644
--- a/App/RobobinApp/Views/MainPage.xaml.cs
+++ b/App/RobobinApp/Views/MainPage.xaml.cs
@@ -1,6 +1,7 @@
 using Microsoft.Maui.Controls;
 using RobobinApp.ViewModels; 
-using RobobinApp.Models; 
+using RobobinApp.Models;
+using System.Diagnostics;
 
 namespace RobobinApp.Views
 {
@@ -19,5 +20,24 @@ namespace RobobinApp.Views
                 drawable.SetGraph(viewModel.Graph);
             }
         }
+
+        private void OnGraphSelected(object sender, EventArgs e)
+        {
+            if (sender is Picker picker && BindingContext is MainPageViewModel viewModel)
+            {
+                // Update the selected graph
+                viewModel.SelectGraphCommand.Execute(picker.SelectedIndex);
+
+                // Refresh the drawable with the new graph
+                var drawable = (GraphicsDrawable)Resources["drawable"];
+                var newGraph = viewModel.Graphs.FirstOrDefault(g => g.Name == viewModel.Graph.Name);
+                drawable.SetGraph(newGraph);
+
+                // Invalidate the GraphicsView to redraw the updated graph
+                GraphicsView.Invalidate(); 
+
+                Debug.WriteLine("New Graph picked and drawn");
+            }
+        }
     }
 }
-- 
GitLab