const std = @import("std"); const rl = @import("raylib"); const c = @import("../common/constants.zig"); const e = @import("../errors.zig"); const st = @import("../common/structures.zig"); const Road = @import("road.zig").Road; pub const Node = struct { /// Possibly unnecessary, but for now it's good as a secondary mean of identification id: usize, /// Node's position on the simulation 'field' pos: rl.Vector2, /// Contains references of all the roads this node is connected to roads: std.ArrayList(*Road), /// Simple constructor pub fn init(new_id: usize, new_pos: rl.Vector2) Node { return .{ .id = new_id, .pos = new_pos, .roads = .empty, }; } /// This function frees the list that holds road references that are connected to this node /// /// Next it invalidates itself (the pointer), making it invalid pub fn deinit(self: *Node, allocator: std.mem.Allocator) !void { if (self.roads.items.len != 0) return e.Entity.AlreadyReferenced; self.roads.deinit(allocator); allocator.destroy(self); } /// Simple function which draws the node pub fn draw(self: *const Node, direct_colour: ?rl.Color) void { const colour = if (direct_colour) |clr| clr else c.NODE_COLOUR; rl.drawCircleV(self.pos, c.NODE_RADIUS, colour); } /// Determines whether the pos (location) is within the snapping radius of the node pub fn withinSnapRadius(self: *const Node, pos: rl.Vector2) bool { return rl.checkCollisionPointCircle(pos, self.pos, c.NODE_SNAP_RADIUS); } /// Determines whether the pos (location) is within the strict (visual representation) radius of the node pub fn withinRadius(self: *const Node, pos: rl.Vector2) bool { return rl.checkCollisionPointCircle(pos, self.pos, c.NODE_RADIUS); } /// Tries to reference the passed road to self /// /// Returns an error if the passed road cannot be appended to the list or if said road is already in the list pub fn referenceRoad(self: *Node, allocator: std.mem.Allocator, road_to_add: *Road) !void { // Note the road_to_add pointer must be one from the roads list as otherwise the pointer is dangling one for (self.roads.items) |road| { if (road == road_to_add) return e.Entity.AlreadyReferenced; } try self.roads.append(allocator, road_to_add); } /// Attempts to unreference the passed road from self (node) /// /// Returns whether the node still has node references (true) or not (false) /// /// Returns an error if the road is not referenced to self in the first place pub fn unreferenceRoad(self: *Node, road_to_remove: *const Road) !void { for (0..self.roads.items.len) |i| { if (self.roads.items[i] != road_to_remove) continue; _ = self.roads.swapRemove(i); return; } return e.Entity.NotFound; } }; // TODO tests // road reference test // pos within node test // deinit test // roads ptr list test