Splitting road implementation preparation
This commit is contained in:
24
src/common/utils.zig
Normal file
24
src/common/utils.zig
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const Vector2 = @import("raylib").Vector2;
|
||||||
|
|
||||||
|
const st = @import("structures.zig");
|
||||||
|
const Node = @import("../infrastructure/node.zig").Node;
|
||||||
|
|
||||||
|
/// Returns distance between two nodes, with the caveat that it doesn't do square root in the end;
|
||||||
|
/// that's because we are interested in relative distance and don't care for the precise number as long as it is in
|
||||||
|
/// correct relation to others
|
||||||
|
///
|
||||||
|
/// This allows us to avoid the (square) rooting operation which is computationally expensive
|
||||||
|
pub fn calculate_length(start: Vector2, end: Vector2) f32 {
|
||||||
|
const x_diff = end.x - start.x;
|
||||||
|
const y_diff = end.y - start.y;
|
||||||
|
|
||||||
|
return x_diff * x_diff + y_diff * y_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Comparator function that compares intersection proximity from the node in order to aid the sorting function
|
||||||
|
pub fn compareIntersections(ctx: *const Node, inter_a: st.IntersectionData, inter_b: st.IntersectionData) bool {
|
||||||
|
const distance_a = ctx.getRelativeInterDistance(inter_a);
|
||||||
|
const distance_b = ctx.getRelativeInterDistance(inter_b);
|
||||||
|
|
||||||
|
return distance_a < distance_b;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ const rl = @import("raylib");
|
|||||||
const c = @import("../common/constants.zig");
|
const c = @import("../common/constants.zig");
|
||||||
const e = @import("../errors.zig");
|
const e = @import("../errors.zig");
|
||||||
const st = @import("../common/structures.zig");
|
const st = @import("../common/structures.zig");
|
||||||
|
const ut = @import("../common/utils.zig");
|
||||||
const Road = @import("road.zig").Road;
|
const Road = @import("road.zig").Road;
|
||||||
|
|
||||||
pub const Node = struct {
|
pub const Node = struct {
|
||||||
@@ -77,6 +78,11 @@ pub const Node = struct {
|
|||||||
|
|
||||||
return e.Entity.NotFound;
|
return e.Entity.NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns distance between the node and intersection object location
|
||||||
|
pub fn getRelativeInterDistance(self: *const Node, intersection: st.IntersectionData) f32 {
|
||||||
|
return ut.calculate_length(intersection.pos, self.pos);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO tests
|
// TODO tests
|
||||||
|
|||||||
@@ -50,11 +50,22 @@ pub const NodeManager = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to find a node which snapping radius covers the pos
|
||||||
|
///
|
||||||
|
/// If it does it returns a reference to it, otherwise null
|
||||||
|
pub fn getNodeIfExists(self: *const NodeManager, pos: Vector2) ?*Node {
|
||||||
|
for (self.nodes.items) |node| {
|
||||||
|
if (node.withinSnapRadius(pos)) return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if there is a node pointer within the snap radius of pos coordinate;
|
/// Checks if there is a node pointer within the snap radius of pos coordinate;
|
||||||
/// otherwise creates a new node and returns its pointer
|
/// otherwise creates a new node and returns its pointer
|
||||||
pub fn getSelectedNode(self: *NodeManager, allocator: std.mem.Allocator, pos: Vector2) !*Node {
|
pub fn getSelectedNode(self: *NodeManager, allocator: std.mem.Allocator, pos: Vector2) !*Node {
|
||||||
for (self.nodes.items) |node| {
|
if (self.getNodeIfExists(pos)) |node| {
|
||||||
if (node.withinSnapRadius(pos)) return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No node is within that position, so we must create a new one
|
// No node is within that position, so we must create a new one
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const rl = @import("raylib");
|
|||||||
|
|
||||||
const c = @import("../common/constants.zig");
|
const c = @import("../common/constants.zig");
|
||||||
const st = @import("../common/structures.zig");
|
const st = @import("../common/structures.zig");
|
||||||
|
const ut = @import("../common/utils.zig");
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
|
|
||||||
pub const Road = struct {
|
pub const Road = struct {
|
||||||
@@ -20,7 +21,7 @@ pub const Road = struct {
|
|||||||
.length = 0,
|
.length = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
road.length = road.calculate_length();
|
road.length = ut.calculate_length(start.pos, end.pos);
|
||||||
return road;
|
return road;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const rl = @import("raylib");
|
const rl = @import("raylib");
|
||||||
|
|
||||||
const st = @import("../common/structures.zig");
|
|
||||||
const e = @import("../errors.zig");
|
const e = @import("../errors.zig");
|
||||||
|
const st = @import("../common/structures.zig");
|
||||||
|
const ut = @import("../common/utils.zig");
|
||||||
const Road = @import("road.zig").Road;
|
const Road = @import("road.zig").Road;
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
|
|
||||||
@@ -93,25 +94,6 @@ pub const RoadManager = struct {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getIntersectingRoads(self: *const RoadManager, allocator: std.mem.Allocator, start: *const Node, end: *const Node) ![]st.IntersectionData {
|
|
||||||
var intersections: std.ArrayList(st.IntersectionData) = .empty;
|
|
||||||
const collision_point: rl.Vector2 = undefined;
|
|
||||||
|
|
||||||
for (self.roads.items) |road| {
|
|
||||||
if (!rl.checkCollisionLines(start.pos, end.pos, road.nodes[0].pos, road.nodes[1].pos, &collision_point))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const intersection = st.IntersectionData {
|
|
||||||
.road = road,
|
|
||||||
.pos = collision_point,
|
|
||||||
};
|
|
||||||
|
|
||||||
try intersections.append(allocator, intersection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections.toOwnedSlice(allocator);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Vector2 = @import("raylib").Vector2;
|
const Vector2 = @import("raylib").Vector2;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ const rl = @import("raylib");
|
|||||||
|
|
||||||
const c = @import("common/constants.zig");
|
const c = @import("common/constants.zig");
|
||||||
const st = @import("common/structures.zig");
|
const st = @import("common/structures.zig");
|
||||||
|
const ut = @import("common/utils.zig");
|
||||||
const Road = @import("infrastructure/road.zig").Road;
|
const Road = @import("infrastructure/road.zig").Road;
|
||||||
|
const Node = @import("infrastructure/node.zig").Node;
|
||||||
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;
|
||||||
|
|
||||||
@@ -143,11 +145,25 @@ pub const Simulator = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (self.node_man.temp_node) |temp| {
|
if (self.node_man.temp_node) |temp| {
|
||||||
|
// Prevents the road from being attached to 2 identical nodes (0 length road)
|
||||||
if (temp.id == cur_node.id) return;
|
if (temp.id == cur_node.id) return;
|
||||||
|
|
||||||
|
// TODO replace with road splitting
|
||||||
self.road_man.addRoad(self.allocator, temp, cur_node) catch |err| {
|
self.road_man.addRoad(self.allocator, temp, cur_node) catch |err| {
|
||||||
std.debug.panic("Failed to add a new road or assigning its nodes: {}\n", .{err});
|
std.debug.panic("Failed to add a new road or assigning its nodes: {}\n", .{err});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const intersections = self.getIntersectingRoads(self.allocator, temp, cur_node) catch |err| {
|
||||||
|
std.debug.panic("Intersection selection failure: {}\n", .{err});
|
||||||
|
};
|
||||||
|
// DEBUG TODO REMOVE
|
||||||
|
std.debug.print("Displaying intersection position and the intersected road:\n", .{});
|
||||||
|
for (0..intersections.len) |i| {
|
||||||
|
const int = intersections[i];
|
||||||
|
std.debug.print("Road ID={d} Pos: ({d}, {d})\n", .{int.road.id, int.pos.x, int.pos.y});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
self.node_man.temp_node = if (self.auto_continue) cur_node else null;
|
self.node_man.temp_node = if (self.auto_continue) cur_node else null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -196,4 +212,46 @@ pub const Simulator = struct {
|
|||||||
|
|
||||||
self.highlighted_entity = null;
|
self.highlighted_entity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getIntersectingRoads(self: *const 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
const intersection = st.IntersectionData {
|
||||||
|
.road = road,
|
||||||
|
.pos = collision_point,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We put a 0 here, just to satisfy the constructor function
|
||||||
|
const node: Node = .init(0, intersection.pos);
|
||||||
|
// If the newly acquired intersection node is within the snapping radius of already existing nodes,
|
||||||
|
// we don't add it to the list
|
||||||
|
for (intersections.items) |inter_collision| {
|
||||||
|
if (node.withinSnapRadius(inter_collision.pos)) continue :outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is an existing node that covers our position within its snapping radius,
|
||||||
|
// then such position will not be saved as intersection
|
||||||
|
if (self.node_man.getNodeIfExists(node.pos) != null) continue :outer;
|
||||||
|
|
||||||
|
try intersections.append(allocator, intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted_intersection = try intersections.toOwnedSlice(allocator);
|
||||||
|
std.sort.block(st.IntersectionData, sorted_intersection, start, ut.compareIntersections);
|
||||||
|
|
||||||
|
return sorted_intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splitRoadsByIntersections(self: *Simulator, intersections: st.IntersectionData, start: *Node, end: *Node) void {
|
||||||
|
_ = intersections; // autofix
|
||||||
|
_ = end; // autofix
|
||||||
|
_ = start; // autofix
|
||||||
|
_ = self; // autofix
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user