Files
traffic-simulator/src/infrastructure/node.zig

86 lines
3.0 KiB
Zig

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