diff --git a/src/infrastructure/road.zig b/src/infrastructure/road.zig index 6aae992..9a0288c 100644 --- a/src/infrastructure/road.zig +++ b/src/infrastructure/road.zig @@ -1,6 +1,7 @@ const rl = @import("raylib"); const c = @import("../common/constants.zig"); +const e = @import("../errors.zig"); const st = @import("../common/structures.zig"); const ut = @import("../common/utils.zig"); const Node = @import("node.zig").Node; @@ -79,6 +80,18 @@ pub const Road = struct { pub fn collides(self: *const Road, pos: rl.Vector2) bool { return rl.checkCollisionPointLine(pos, self.nodes[0].pos, self.nodes[1].pos, c.ROAD_SIZE); } + + /// Updates node reference old_node => new node; returns error if old_node does not exist + pub fn updateNodeReference(self: *Road, old_node: *Node, new_node: *Node) !void { + for (0..self.nodes.len) |i| { + if (self.nodes[i] != old_node) continue; + + self.nodes[i] = new_node; + return; + } + + return e.Entity.NotFound; + } }; const std = @import("std"); @@ -109,4 +122,7 @@ test "valid road nodes" { try expect(road.nodes[0].id == 34); try expect(road.nodes[1].id == 227); -} \ No newline at end of file +} + +// TODO tests +// test every case error for every function that can return an error \ No newline at end of file diff --git a/src/simulator.zig b/src/simulator.zig index 9644f5d..fbae2dc 100644 --- a/src/simulator.zig +++ b/src/simulator.zig @@ -288,18 +288,77 @@ pub const Simulator = struct { } /// Takes the data about intersections and adds new nodes there alongside with linking existing roads to them - fn splitRoadsByIntersections(self: *Simulator, intersections: []st.IntersectionData, start: *Node, end: *Node) void { + /// + /// Important: This function assumes the intersection array is sorted by distance from the start node (ascending) + fn splitRoadsByIntersections(self: *Simulator, intersections: []st.IntersectionData, start: *Node, end: *Node) !void { if (intersections.len == 0) { self.road_man.addRoad(self.allocator, start, end) catch |err| { - std.debug.panic("Failed to create a road connecting the origin nodes: {}\n", .{err}); + std.debug.panic("Failed creating the road out of origin nodes: {}\n", .{err}); }; - return; } - for (0..intersections.len) |i| { - _ = i; // autofix + // Here we connect the start node with the first intersection node (via road) + const first_node = self.node_man.getSelectedNode(self.allocator, intersections[0].pos) catch |err| { + std.debug.panic("Failed to add the first node of the intersection: {}\n", .{err}); + }; + self.road_man.addRoad(self.allocator, start, first_node) catch |err| { + std.debug.panic("Failed to add a road of origin (start) node and the first intersection node: {}\n", .{err}); + }; + for (0..intersections.len) |i| { + const intersection = intersections[i]; + + // The node created at the point of intersection + const new_node = self.node_man.getSelectedNode(self.allocator, intersection.pos) catch |err| { + std.debug.panic("Failed to create a node based on the intersection index {d}: {}\n", .{ + i, + err + }); + }; + + // Pointer to the node that borders the road that was intersected + // This node and the new_node will become nodes for the new road being created + const old_node_of_road = intersection.road.nodes[1]; + + // The old road that was intersected now borders the new node + // and the old node is removed from the road's end node reference, + // as is the end node's road reference + + // So the intersected road loses old node (at the far end) and gets new node that intersects it + intersection.road.updateNodeReference(old_node_of_road, new_node) catch |err| { + std.debug.panic("Failed to update the road's node references: {}\n", .{err}); + }; + + // Now we add the road (to the road list) and references the road at both bounding nodes + self.road_man.addRoad(self.allocator, new_node, old_node_of_road) catch |err| { + std.debug.panic("Failed to create a road of new node and former node of prior intersecting road", .{ + err + }); + }; + + // Here we work on creating new roads between intersection nodes and as such because we need nodes + // at 2 different intersections, it means we have to be sure next one exists + if (i == intersections.len - 1) continue; + + const next_intersection = self.node_man.getSelectedNode(self.allocator, intersections[i+1].pos) catch |err| { + std.debug.panic("Failed to create node of next intersection (current index={d}: {}\n", .{i, err}); + }; + + // Creating the road connecting current intersection with the next one + self.road_man.addRoad(self.allocator, new_node, next_intersection) catch |err| { + std.debug.panic("Failed to create the road of current and next intersection nodes: {}\n", .{err}); + }; } + + // Finally we create final road by connecting last intersection node to the end origin node + const final_intersection_pos = intersections[intersections.len - 1].pos; + const final_intersection_node = self.node_man.getSelectedNode(self.allocator, final_intersection_pos) catch |err| { + std.debug.panic("Failed to create node based on last intersection position: {}\n", .{err}); + }; + + self.road_man.addRoad(self.allocator, final_intersection_node, end) catch |err| { + std.debug.panic("Failed to create a road of final intersection and end origin node: {}\n", .{err}); + }; } }; \ No newline at end of file