Intersection sorting implemented
This commit is contained in:
@@ -82,7 +82,7 @@ pub const NodeManager = struct {
|
|||||||
|
|
||||||
/// generates finds the last element in the list and returns id + 1 or 0 if there are no elements in the list
|
/// generates finds the last element in the list and returns id + 1 or 0 if there are no elements in the list
|
||||||
fn getNewID(self: *const NodeManager) usize {
|
fn getNewID(self: *const NodeManager) usize {
|
||||||
return if (self.getLastRef()) |ref| ref.*.id + 1 else 0;
|
return if (self.nodes.getLastOrNull()) |last| last.id + 1 else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates through all nodes and runs the deinit procedure on each of them
|
/// Iterates through all nodes and runs the deinit procedure on each of them
|
||||||
@@ -98,6 +98,11 @@ pub const NodeManager = struct {
|
|||||||
// This also means we don't have to deinit it, since it has no elements
|
// This also means we don't have to deinit it, since it has no elements
|
||||||
if (node_to_remove.roads.items.len > 0) return;
|
if (node_to_remove.roads.items.len > 0) return;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// When a node gets removed the empty space left by now non-existant node will get swapped with another node
|
||||||
|
// In practice this however means that pointers to the node that gets swapped will be invalid
|
||||||
|
// causing fatal errors
|
||||||
|
|
||||||
for (self.nodes.items, 0..) |*node, i| {
|
for (self.nodes.items, 0..) |*node, i| {
|
||||||
if (node.id != node_to_remove.id) continue;
|
if (node.id != node_to_remove.id) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -57,12 +57,11 @@ pub const RoadManager = struct {
|
|||||||
|
|
||||||
/// Generates finds the last element in the list and returns id + 1 or 0 if there are no elements in the list
|
/// Generates finds the last element in the list and returns id + 1 or 0 if there are no elements in the list
|
||||||
fn getNewID(self: *const RoadManager) usize {
|
fn getNewID(self: *const RoadManager) usize {
|
||||||
return if (self.getLastRef()) |ref| ref.*.id + 1 else 0;
|
return if (self.roads.getLastOrNull()) |last| last.id + 1 else 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the road which reference is passed in; returns error if the road is invalid
|
/// Removes the road which reference is passed in; returns error if the road is invalid
|
||||||
pub fn remove(self: *RoadManager, road_to_remove: *Road) !void {
|
pub fn remove(self: *RoadManager, road_to_remove: *Road) !void {
|
||||||
// todo fix leak
|
|
||||||
try road_to_remove.unreferenceNodes();
|
try road_to_remove.unreferenceNodes();
|
||||||
|
|
||||||
for (self.roads.items, 0..) |*road, i| {
|
for (self.roads.items, 0..) |*road, i| {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const rl = @import("raylib");
|
|||||||
|
|
||||||
const c = @import("constants.zig");
|
const c = @import("constants.zig");
|
||||||
const st = @import("structures.zig");
|
const st = @import("structures.zig");
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
const NodeManager = @import("infrastructure/node_manager.zig").NodeManager;
|
const NodeManager = @import("infrastructure/node_manager.zig").NodeManager;
|
||||||
const RoadManager = @import("infrastructure/road_manager.zig").RoadManager;
|
const RoadManager = @import("infrastructure/road_manager.zig").RoadManager;
|
||||||
@@ -19,8 +20,6 @@ pub const Simulator = struct {
|
|||||||
display_details: bool,
|
display_details: bool,
|
||||||
/// Tracks whether to automatically start build a new road after the creation of previous one is finished
|
/// Tracks whether to automatically start build a new road after the creation of previous one is finished
|
||||||
auto_continue: bool,
|
auto_continue: bool,
|
||||||
/// Displays intersection data for easier implementation and debugging
|
|
||||||
debug_intersection_data: std.ArrayList(st.IntersectionData),
|
|
||||||
mode: st.Mode,
|
mode: st.Mode,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !Simulator {
|
pub fn init(allocator: std.mem.Allocator) !Simulator {
|
||||||
@@ -30,7 +29,6 @@ pub const Simulator = struct {
|
|||||||
.road_man = try .init(allocator),
|
.road_man = try .init(allocator),
|
||||||
.display_details = false,
|
.display_details = false,
|
||||||
.auto_continue = false,
|
.auto_continue = false,
|
||||||
.debug_intersection_data = .empty,
|
|
||||||
.mode = .VISUAL,
|
.mode = .VISUAL,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -38,7 +36,6 @@ pub const Simulator = struct {
|
|||||||
pub fn deinit(self: *Simulator) void {
|
pub fn deinit(self: *Simulator) void {
|
||||||
self.node_man.deinit(self.allocator);
|
self.node_man.deinit(self.allocator);
|
||||||
self.road_man.deinit(self.allocator);
|
self.road_man.deinit(self.allocator);
|
||||||
self.debug_intersection_data.deinit(self.allocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Input handling function that is exposed to the public
|
/// Input handling function that is exposed to the public
|
||||||
@@ -53,7 +50,6 @@ pub const Simulator = struct {
|
|||||||
self.auto_continue = rl.isKeyDown(.left_control);
|
self.auto_continue = rl.isKeyDown(.left_control);
|
||||||
|
|
||||||
if (rl.isKeyReleased(.c) and self.mode == .DELETE) {
|
if (rl.isKeyReleased(.c) and self.mode == .DELETE) {
|
||||||
self.debug_intersection_data.clearRetainingCapacity();
|
|
||||||
self.node_man.temp_node = null;
|
self.node_man.temp_node = null;
|
||||||
self.road_man.roads.clearRetainingCapacity();
|
self.road_man.roads.clearRetainingCapacity();
|
||||||
self.node_man.clear(self.allocator);
|
self.node_man.clear(self.allocator);
|
||||||
@@ -104,9 +100,16 @@ pub const Simulator = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// get intersections made
|
// get intersections made
|
||||||
self.getIntersectingRoads(temp, node) catch |err| {
|
const data = self.getIntersectingRoads(self.allocator, temp, node) catch |err| {
|
||||||
std.debug.panic("Failed to save intersection data: {}\n", .{err});
|
std.debug.panic("Failed to save intersection data: {}\n", .{err});
|
||||||
};
|
};
|
||||||
|
defer self.allocator.free(data);
|
||||||
|
|
||||||
|
std.debug.print("Displaying intersection points in order from start (temp):\n", .{});
|
||||||
|
for (0..data.len) |i| {
|
||||||
|
std.debug.print("{d}: ({d}, {d})\n", .{i+1, data[i].point.x, data[i].point.y});
|
||||||
|
}
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
|
||||||
self.node_man.temp_node = if (self.auto_continue) node else null;
|
self.node_man.temp_node = if (self.auto_continue) node else null;
|
||||||
}
|
}
|
||||||
@@ -127,11 +130,6 @@ pub const Simulator = struct {
|
|||||||
self.node_man.draw(self.display_details);
|
self.node_man.draw(self.display_details);
|
||||||
self.drawUI();
|
self.drawUI();
|
||||||
|
|
||||||
// Display intersection 'nodes'
|
|
||||||
for (self.debug_intersection_data.items) |intersection| {
|
|
||||||
rl.drawCircleV(intersection.point, c.NODE_RADIUS / 2, .red);
|
|
||||||
}
|
|
||||||
|
|
||||||
rl.clearBackground(.light_gray);
|
rl.clearBackground(.light_gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,25 +165,44 @@ pub const Simulator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets list of pointers of all roads that 'collide' with the road bounded by the nodes we pass into it
|
/// Gets list of pointers of all roads that 'collide' with the road bounded by the nodes we pass into it
|
||||||
fn getIntersectingRoads(self: *Simulator, start: *const Node, end: *const Node) !void {
|
fn getIntersectingRoads(self: *Simulator, allocator: std.mem.Allocator, start: *const Node, end: *const Node) ![]st.IntersectionData {
|
||||||
|
var intersections: std.ArrayList(st.IntersectionData) = .empty;
|
||||||
var collision_point: rl.Vector2 = undefined;
|
var collision_point: rl.Vector2 = undefined;
|
||||||
|
|
||||||
outer: for (self.road_man.roads.items) |*road| {
|
outer: for (self.road_man.roads.items) |*road| {
|
||||||
if (!rl.checkCollisionLines(start.pos, end.pos, road.nodes[0].pos, road.nodes[1].pos, &collision_point)) continue;
|
// If there is no collision check the next road
|
||||||
const intersection = st.IntersectionData {
|
if (!rl.checkCollisionLines(
|
||||||
|
start.pos,
|
||||||
|
end.pos,
|
||||||
|
road.nodes[0].pos,
|
||||||
|
road.nodes[1].pos,
|
||||||
|
&collision_point)) continue;
|
||||||
|
|
||||||
|
// Save the collision info
|
||||||
|
const data = st.IntersectionData {
|
||||||
.road = road,
|
.road = road,
|
||||||
.point = collision_point,
|
.point = collision_point,
|
||||||
};
|
};
|
||||||
|
|
||||||
const node: Node = .init(0, intersection.point);
|
const node: Node = .init(0, data.point);
|
||||||
// here we need to check if the points captured already are already within the reach
|
// here we need to check if the points captured already are already within the reach
|
||||||
for (self.debug_intersection_data.items) |collision| {
|
for (intersections.items) |collision| {
|
||||||
if (node.withinSnappingRadius(collision.point))
|
if (node.withinSnappingRadius(collision.point))
|
||||||
continue :outer;
|
continue :outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.node_man.getNodeWithinRadius(intersection.point) == null) try self.debug_intersection_data.append(self.allocator, intersection);
|
// This checks whether our collision point is actually to close to the existing node(s)
|
||||||
|
// to form another intersection there
|
||||||
|
if (self.node_man.getNodeWithinRadius(data.point) != null) continue;
|
||||||
|
|
||||||
|
try intersections.append(self.allocator, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we must sort the items by the distance from the first (usually temp) node
|
||||||
|
const sorted_intersections = try intersections.toOwnedSlice(allocator);
|
||||||
|
std.sort.block(st.IntersectionData, sorted_intersections, start, utils.compareIntersections);
|
||||||
|
|
||||||
|
return sorted_intersections;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *Simulator) void {
|
pub fn update(self: *Simulator) void {
|
||||||
|
|||||||
@@ -2,13 +2,21 @@ const Vector2 = @import("raylib").Vector2;
|
|||||||
|
|
||||||
const Road = @import("infrastructure/road.zig").Road;
|
const Road = @import("infrastructure/road.zig").Road;
|
||||||
|
|
||||||
|
/// Represents the data, particularly used in the instance when we draw over already existing roads
|
||||||
pub const IntersectionData = struct {
|
pub const IntersectionData = struct {
|
||||||
|
/// Tracks the road we intersected
|
||||||
road: *Road,
|
road: *Road,
|
||||||
|
/// Exact point where the road above was intersected
|
||||||
point: Vector2,
|
point: Vector2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Tracks different modes of interaction with the simulation
|
||||||
pub const Mode = enum {
|
pub const Mode = enum {
|
||||||
|
/// Represents visual, read-only mode
|
||||||
VISUAL,
|
VISUAL,
|
||||||
|
/// Represents build mode
|
||||||
BUILD,
|
BUILD,
|
||||||
|
/// Represents deleting or modifying existing entities
|
||||||
|
/// May also be called edit mode in the future
|
||||||
DELETE
|
DELETE
|
||||||
};
|
};
|
||||||
16
src/utils.zig
Normal file
16
src/utils.zig
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const st = @import("structures.zig");
|
||||||
|
const Node = @import("infrastructure/node.zig").Node;
|
||||||
|
|
||||||
|
pub fn compareIntersections(ctx: *const Node, inter_a: st.IntersectionData, inter_b: st.IntersectionData) bool {
|
||||||
|
const distance_a = getRelativeInterDistance(ctx, inter_a);
|
||||||
|
const distance_b = getRelativeInterDistance(ctx, inter_b);
|
||||||
|
|
||||||
|
return distance_a < distance_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getRelativeInterDistance(ctx: *const Node, intersection: st.IntersectionData) f32 {
|
||||||
|
const x_diff = intersection.point.x - ctx.pos.x;
|
||||||
|
const y_diff = intersection.point.y - ctx.pos.y;
|
||||||
|
|
||||||
|
return x_diff * x_diff + y_diff * y_diff;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user