diff --git a/App/RobobinApp/Networking/WifiManager.cs b/App/RobobinApp/Networking/WifiManager.cs index b034c3496698af9c8bce55c84ae0feccec2db2eb..ac5bd3c69e975b6ef4b56eb928f4b4ad67b73172 100644 --- a/App/RobobinApp/Networking/WifiManager.cs +++ b/App/RobobinApp/Networking/WifiManager.cs @@ -209,7 +209,7 @@ namespace RobobinApp.Networking public async Task SendCallMeRequest(string endPoint) { Debug.WriteLine("Call me request"); - await SendMessageAsync("CALLME " + endPoint); + await SendMessageAsync("CALLMELIDAR " + endPoint); } public async Task SendPingMessage() diff --git a/App/RobobinApp/Resources/Images/lab_map.jpg b/App/RobobinApp/Resources/Images/lab_map.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d7ac60e7dc9e87a9b961d14535710a373025f43 Binary files /dev/null and b/App/RobobinApp/Resources/Images/lab_map.jpg differ diff --git a/App/RobobinApp/RobobinApp.csproj b/App/RobobinApp/RobobinApp.csproj index a8e008bc3cd5f030d851ba9a7f601d16378528d6..ecc4a079aa94816911a4b1dd42710bd42213e475 100644 --- a/App/RobobinApp/RobobinApp.csproj +++ b/App/RobobinApp/RobobinApp.csproj @@ -48,11 +48,21 @@ <AndroidResource Remove="Platforms\Android\Resources\mipmap\robobinlogo1.png" /> </ItemGroup> + <ItemGroup> + <MauiImage Remove="Resources\Images\lab_map.jpg" /> + </ItemGroup> + <ItemGroup> <None Remove="Platforms\Android\Resources\drawable\bin.svg" /> <None Remove="Platforms\Android\Resources\mipmap\robobinlogo1.png" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\Images\lab_map.jpg"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" /> <PackageReference Include="Microsoft.Maui.Controls" Version="8.0.91" /> diff --git a/App/RobobinApp/ViewModels/MainPageViewModel.cs b/App/RobobinApp/ViewModels/MainPageViewModel.cs index a3477a1d0ff40f31f1e1d4e42b9b69a2ff06a3cd..52c0b7a0a103657e6e347fe8bc27474382fb4c05 100644 --- a/App/RobobinApp/ViewModels/MainPageViewModel.cs +++ b/App/RobobinApp/ViewModels/MainPageViewModel.cs @@ -1,6 +1,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; +using System.Linq; using System.Runtime.CompilerServices; using System.Windows.Input; using Microsoft.Extensions.Logging; @@ -58,15 +59,26 @@ namespace RobobinApp.ViewModels ToggleModeCommand = new Command(async () => await OnToggleMode()); GetNewGraphCommand = new Command(async () => await GetNewGraph()); var graphNodes1 = new List<Node> - -{ - new Node("No graph loaded", 50, 50), - -}; - - var graphMatrix1 = CalculatePolarConnections(graphNodes1, new bool[,] { - { false } }); + new Node("1", 347, 276), + new Node("2", 321, 280), + new Node("3", 350, 318), + new Node("4", 326, 317), + new Node("5", 357, 360), + new Node("6", 328, 355), + new Node("7", 355, 404), + new Node("8", 332, 390), + new Node("9", 359, 455), + new Node("10", 334, 425), + new Node("11", 423, 443), + new Node("12", 417, 400), + new Node("13", 417, 355), + new Node("14", 416, 313), + new Node("15", 417, 269) + }; + + + var graphMatrix1 = CalculatePolarConnections(graphNodes1, new bool[graphNodes1.Count, graphNodes1.Count]); var mapdata = App.WifiManager.MapData; Debug.WriteLine($"Mapdata : { mapdata}"); var graphNodes = graphNodes1; diff --git a/App/RobobinApp/Views/CentreGraph.xaml.cs b/App/RobobinApp/Views/CentreGraph.xaml.cs index 113ac5412ed3565ddabd0d1993610521c4a56f31..d27595eaf9e4ea535aef49211e8b3b016191e390 100644 --- a/App/RobobinApp/Views/CentreGraph.xaml.cs +++ b/App/RobobinApp/Views/CentreGraph.xaml.cs @@ -1,42 +1,30 @@ using Microsoft.Maui.Graphics; using Robobin.Models; -using RobobinApp.Models; using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; namespace RobobinApp.Views { public class GraphicsDrawable : IDrawable { private Graph _graph; - private (float, float) _location; - public const float BaseNodeRadius = 5f; // Make this public if needed elsewhere + public const float NodeRadius = 5f; // Fixed radius for nodes private static readonly Color DefaultNodeColor = Colors.Red; - private static readonly Color HomeNodeColor = Colors.Green; - private static readonly Color BackgroundColor = Color.FromHex("#2C2F33"); - private static readonly Color ConnectionColor = Colors.Grey; - private static readonly Color HighlightedNodeColor = Colors.Yellow; // For the highlighted node - private static readonly Color PathColor = Colors.Blue; // For the path + private static readonly Color HighlightedNodeColor = Colors.Yellow; // Highlighted node color private RectF storedDirtyRect; - public float CurrentScale { get; private set; } = 1.0f; - public (float X, float Y) CurrentOffset { get; private set; } = (0, 0); - private Node _highlightedNode; - private List<Node> _path; public void SetGraph(Graph graph) { _graph = graph ?? throw new ArgumentNullException(nameof(graph)); _highlightedNode = null; - _path = null; } - public void SetLocation((float, float) location) + public void HighlightNode(Node node) { - _location = location; + _highlightedNode = node; } public void Draw(ICanvas canvas, RectF dirtyRect) @@ -44,127 +32,68 @@ namespace RobobinApp.Views storedDirtyRect = dirtyRect; if (_graph == null) return; + // Draw the background image DrawBackground(canvas, dirtyRect); - (float minX, float minY, float maxX, float maxY) = CalculateBounds(); - - CurrentScale = CalculateScale(dirtyRect, minX, minY, maxX, maxY); - (float offsetX, float offsetY) = CalculateOffsets(dirtyRect, minX, minY, maxX, maxY, CurrentScale); - CurrentOffset = (offsetX, offsetY); - float nodeRadius = BaseNodeRadius * CurrentScale; - - DrawConnections(canvas, CurrentScale, offsetX, offsetY); - DrawPath(canvas, CurrentScale, offsetX, offsetY); - DrawNodes(canvas, CurrentScale, offsetX, offsetY, nodeRadius, _highlightedNode); - DrawLocation(canvas, CurrentScale, offsetX, offsetY); - } - - private void DrawLocation(ICanvas canvas, float scale, float offsetX, float offsetY) - { - Debug.WriteLine($"Drawing Location {_location.Item1} {_location.Item2}"); - float scaledX = _location.Item1 * scale + offsetX; - float flippedY = storedDirtyRect.Height - (_location.Item2 * scale + offsetY); - - canvas.FillColor = Colors.Yellow; - canvas.FillCircle(scaledX, flippedY, 5); - canvas.FontColor = Colors.White; - canvas.DrawString($"Robobin ({_location.Item1} {_location.Item2})", scaledX + 7, flippedY - 5, HorizontalAlignment.Left); + // Draw the nodes on top of the image + DrawNodes(canvas, NodeRadius, _highlightedNode); } private void DrawBackground(ICanvas canvas, RectF dirtyRect) { - canvas.FillColor = BackgroundColor; - canvas.FillRectangle(dirtyRect); - } - - private (float minX, float minY, float maxX, float maxY) CalculateBounds() - { - 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); - return (minX, minY, maxX, maxY); - } - - private float CalculateScale(RectF dirtyRect, float minX, float minY, float maxX, float maxY) - { - float graphWidth = maxX - minX; - float graphHeight = maxY - minY; - float scaleX = dirtyRect.Width / graphWidth; - float scaleY = dirtyRect.Height / graphHeight; - return Math.Min(scaleX, scaleY) * 0.8f; - } - - private (float offsetX, float offsetY) CalculateOffsets(RectF dirtyRect, float minX, float minY, float maxX, float maxY, float scale) - { - float offsetX = dirtyRect.Center.X - ((minX + maxX) * 0.5f) * scale; - float offsetY = dirtyRect.Center.Y - ((minY + maxY) * 0.5f) * scale; - return (offsetX, offsetY); - } - - private void DrawConnections(ICanvas canvas, float scale, float offsetX, float offsetY) - { - canvas.StrokeColor = ConnectionColor; - canvas.StrokeSize = 2; - - foreach (var node in _graph.Nodes) + try { - int nodeIndex = _graph.Nodes.IndexOf(node); - float startX = node.X * scale + offsetX; - float startY = storedDirtyRect.Height - (node.Y * scale + offsetY); // flip Y + // Load the embedded image resource + var assembly = typeof(GraphicsDrawable).Assembly; + var resourceStream = assembly.GetManifestResourceStream("Robobin.Resources.Images.lab_map.jpg"); - for (int j = 0; j < _graph.Nodes.Count; j++) + if (resourceStream != null) { - var (magnitude, angle) = _graph.AdjacencyMatrix[nodeIndex, j]; - if (magnitude > 0) - { - float targetX = (node.X + magnitude * MathF.Cos(MathF.PI * angle / 180)) * scale + offsetX; - float targetRawY = (node.Y + magnitude * MathF.Sin(MathF.PI * angle / 180)) * scale + offsetY; - float targetY = storedDirtyRect.Height - targetRawY; // flip Y - - canvas.DrawLine(startX, startY, targetX, targetY); - } + var image = Microsoft.Maui.Graphics.Platform.PlatformImage.FromStream(resourceStream); + canvas.DrawImage(image, dirtyRect.Left, dirtyRect.Top, dirtyRect.Width, dirtyRect.Height); + } + else + { + throw new Exception("Embedded resource not found."); } } + catch (Exception ex) + { + Debug.WriteLine($"Error loading image: {ex.Message}"); + + // Fallback: fill background with a color if the image is unavailable + canvas.FillColor = Colors.Black; + canvas.FillRectangle(dirtyRect); + } } - private void DrawNodes(ICanvas canvas, float scale, float offsetX, float offsetY, float nodeRadius, Node highlightedNode) + private void DrawNodes(ICanvas canvas, float nodeRadius, Node highlightedNode) { foreach (var node in _graph.Nodes) { - float scaledX = node.X * scale + offsetX; - float flippedY = storedDirtyRect.Height - (node.Y * scale + offsetY); // flip Y + float x = node.X; // Use the original X-coordinate + float y = node.Y; // Use the original Y-coordinate + + // Set fill color based on whether the node is highlighted + canvas.FillColor = (highlightedNode == node) ? HighlightedNodeColor : DefaultNodeColor; - canvas.FillColor = (highlightedNode == node) - ? HighlightedNodeColor - : (node.Name == "Home" ? HomeNodeColor : DefaultNodeColor); + // Draw the node as a circle + canvas.FillCircle(x, y, nodeRadius); - canvas.FillCircle(scaledX, flippedY, nodeRadius); + // Optionally, draw node name or other details canvas.FontColor = Colors.White; - var nodeDetails = $"{node.Name}"; - canvas.DrawString(nodeDetails, scaledX + nodeRadius + 2, flippedY - nodeRadius, HorizontalAlignment.Left); + canvas.DrawString(node.Name, x + nodeRadius + 2, y - nodeRadius, HorizontalAlignment.Left); } } - public Node FindNearestNode(float clickX, float clickY, float scale, float offsetX, float offsetY) + public Node FindNearestNode(float tapPointX, float tapPointY) { - // The coordinates given (clickX, clickY) are in the original coordinate system - // where the y-axis goes down. We must transform them similarly to how we did - // when drawing: flip the Y using storedDirtyRect. - float flippedClickY = clickY; - - Node nearestNode = null; float minDistance = float.MaxValue; + Node nearestNode = null; foreach (var node in _graph.Nodes) { - float scaledX = node.X * scale + offsetX; - // Flip Y when comparing distances - float flippedY = storedDirtyRect.Height - (node.Y * scale + offsetY); - - float dx = clickX - scaledX; - float dy = flippedClickY - flippedY; - float distance = MathF.Sqrt(dx * dx + dy * dy); + float distance = (float)Math.Sqrt(Math.Pow(node.X - tapPointX, 2) + Math.Pow(node.Y - tapPointY, 2)); if (distance < minDistance) { minDistance = distance; @@ -174,109 +103,5 @@ namespace RobobinApp.Views return nearestNode; } - - public void HighlightNode(Node node) - { - _highlightedNode = node; - } - - public List<Node> AStarPathfinding(Node startNode, Node targetNode) - { - var openSet = new List<Node> { startNode }; - var cameFrom = new Dictionary<Node, Node>(); - var gScore = new Dictionary<Node, float>(); - var fScore = new Dictionary<Node, float>(); - - foreach (var node in _graph.Nodes) - { - gScore[node] = float.MaxValue; - fScore[node] = float.MaxValue; - } - gScore[startNode] = 0; - fScore[startNode] = Heuristic(startNode, targetNode); - - while (openSet.Count > 0) - { - Node currentNode = openSet.OrderBy(node => fScore[node]).First(); - - if (currentNode == targetNode) - { - return ReconstructPath(cameFrom, currentNode); - } - - openSet.Remove(currentNode); - - foreach (var edge in currentNode.Edges) - { - Node neighbor = edge.TargetNode; - float tentativeGScore = gScore[currentNode] + edge.Cost; - - if (tentativeGScore < gScore[neighbor]) - { - cameFrom[neighbor] = currentNode; - gScore[neighbor] = tentativeGScore; - fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor, targetNode); - - if (!openSet.Contains(neighbor)) - { - openSet.Add(neighbor); - } - } - } - } - - return new List<Node>(); - } - - private float Heuristic(Node a, Node b) - { - return MathF.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y)); - } - - private List<Node> ReconstructPath(Dictionary<Node, Node> cameFrom, Node currentNode) - { - var totalPath = new List<Node> { currentNode }; - - while (cameFrom.ContainsKey(currentNode)) - { - currentNode = cameFrom[currentNode]; - totalPath.Add(currentNode); - } - - totalPath.Reverse(); - return totalPath; - } - - public Node GetHomeNode() - { - return _graph.Nodes.FirstOrDefault(n => n.Name == "Home"); - } - - public List<Node> Path - { - get => _path; - set => _path = value; - } - - private void DrawPath(ICanvas canvas, float scale, float offsetX, float offsetY) - { - if (_path != null && _path.Count > 0) - { - canvas.StrokeColor = PathColor; - canvas.StrokeSize = 3; - - for (int i = 0; i < _path.Count - 1; i++) - { - float startX = _path[i].X * scale + offsetX; - float startRawY = _path[i].Y * scale + offsetY; - float startY = storedDirtyRect.Height - startRawY; // flip Y - float endX = _path[i + 1].X * scale + offsetX; - float endRawY = _path[i + 1].Y * scale + offsetY; - float endY = storedDirtyRect.Height - endRawY; // flip Y - - canvas.DrawLine(startX, startY, endX, endY); - } - } - } } } diff --git a/App/RobobinApp/Views/MainPage.xaml.cs b/App/RobobinApp/Views/MainPage.xaml.cs index 533e36ad3deccfbb9d762b15e0ab72f50a9c730a..3022db93b3b46d8817e10f8d0278ded97ec8c5e4 100644 --- a/App/RobobinApp/Views/MainPage.xaml.cs +++ b/App/RobobinApp/Views/MainPage.xaml.cs @@ -52,40 +52,32 @@ namespace RobobinApp.Views private void OnGraphicsViewTapped(object sender, TappedEventArgs e) { - if (App.WifiManager.Mode != "Call") - { - DisplayAlert("NO CALL","Bin must be in call mode to use this feature!","Sorry!"); - return; - } + //if (App.WifiManager.Mode != "Call") + //{ + // DisplayAlert("NO CALL","Bin must be in call mode to use this feature!","Sorry!"); + // return; + //} var tapPoint = e.GetPosition(GraphicsView); var drawable = (GraphicsDrawable)Resources["drawable"]; - float scale = drawable.CurrentScale; - var offset = drawable.CurrentOffset; + var tapPointX = (float)tapPoint.Value.X; var tapPointY = (float)tapPoint.Value.Y; + Debug.WriteLine($"position: {tapPointX}, {tapPointY}"); (float,float) endPoint = (tapPointX, tapPointY); - var nearestNode = drawable.FindNearestNode(tapPointX, tapPointY, scale, offset.X, offset.Y); - Task task = App.WifiManager.SendCallMeRequest(nearestNode.Name); - // Highlight the nearest node - drawable.HighlightNode(nearestNode); + var nearestNode = drawable.FindNearestNode(tapPointX, tapPointY); + + + if (nearestNode != null) { - // Find the home node - Node homeNode = drawable.GetHomeNode(); - - if (homeNode != null) - { - - List<Node> path = drawable.AStarPathfinding(nearestNode, homeNode); - drawable.Path = path; - GraphicsView.Invalidate(); - } - + Task task = App.WifiManager.SendCallMeRequest(nearestNode.Name); + // Highlight the nearest node + drawable.HighlightNode(nearestNode); DisplayAlert("Node Clicked", $"You clicked on node: {nearestNode.Name}", "OK"); } else @@ -113,7 +105,7 @@ namespace RobobinApp.Views { var drawable = (GraphicsDrawable)Resources["drawable"]; Debug.WriteLine($"VM Location { viewModel.Location }"); - drawable.SetLocation(viewModel.Location); + //drawable.SetLocation(viewModel.Location); drawable.SetGraph(viewModel.Graph); GraphicsView.Invalidate(); // Redraw the GraphicsView Debug.WriteLine("Graph updated and redrawn."); diff --git a/App/RobobinApp/Views/MainPage_Android.xaml.cs b/App/RobobinApp/Views/MainPage_Android.xaml.cs index f7059f4065ca2314d5558c12d3d66f1efee7a807..9a93b832f92eaf59f1e00d8895a509af2c819ce6 100644 --- a/App/RobobinApp/Views/MainPage_Android.xaml.cs +++ b/App/RobobinApp/Views/MainPage_Android.xaml.cs @@ -34,33 +34,21 @@ namespace RobobinApp.Views var tapPoint = e.GetPosition(GraphicsView); var drawable = (GraphicsDrawable)Resources["drawable"]; - float scale = drawable.CurrentScale; - var offset = drawable.CurrentOffset; - + var tapPointX = (float)tapPoint.Value.X; var tapPointY = (float)tapPoint.Value.Y; (float, float) endPoint = (tapPointX, tapPointY); - var nearestNode = drawable.FindNearestNode(tapPointX, tapPointY, scale, offset.X, offset.Y); + var nearestNode = drawable.FindNearestNode(tapPointX, tapPointY); Task task = App.WifiManager.SendCallMeRequest(nearestNode.Name); // Highlight the nearest node drawable.HighlightNode(nearestNode); if (nearestNode != null) { - // Find the home node - Node homeNode = drawable.GetHomeNode(); - - if (homeNode != null) - { - - List<Node> path = drawable.AStarPathfinding(nearestNode, homeNode); - drawable.Path = path; - GraphicsView.Invalidate(); - } - + DisplayAlert("Node Clicked", $"You clicked on node: {nearestNode.Name}", "OK"); } else