The Smart Vehicle Traffic Simulation is an advanced, multi-dimensional simulation system designed to model electric vehicle (EV) movement within a complex, dynamic traffic network. By integrating intelligent pathfinding, real-time traffic signal management, and comprehensive visualization, this project offers a cutting-edge approach to understanding urban mobility and traffic flow.
- Real-time EV Simulation
- Dynamic and intelligent vehicle movement algorithms
- Comprehensive battery charge monitoring
- Smart charging system integration
- Support for multiple vehicle types and configurations
- Adaptive Traffic Control
- Intelligent traffic signal optimization
- Advanced collision prevention mechanisms
- Smart pathfinding using native Dijkstra algorithm
- Interactive and configurable traffic node system
- Multi-modal Visualization
- Web-based interactive GUI powered by Phaser.js
- Detailed terminal-based visualization option
- Real-time vehicle position tracking
- Comprehensive traffic signal status display
- Backend: Java 17 with Spring Boot
- Pathfinding: Native C++ implementation with JNI
- Frontend: Phaser.js for web visualization
- Algorithms: Dijkstra's shortest path algorithm
The simulation leverages a sophisticated computational model that combines:
- Graph-based traffic network representation
- Probabilistic vehicle behavior modeling
- Real-time state machine for traffic signals
- Energy consumption and charging dynamics simulation
- The traffic system works with any kind of map made in this editor.
- Eases the process of creating customized maps
- Edit existing maps, or make new ones!
classDiagram
class GameMap {
-static GameMap instance
-int width
-int height
-Map<String, Node> roadNetwork
-RoadMapParser roadMapParser
+GameMap()
-loadMap(String filename, String signalMapPath) void
+static getInstance() GameMap
+isWalkable(int x, int y) boolean
+getObstacleMap() boolean[][]
+getWidth() int
+getHeight() int
+printMap() void
+getRoadNode(int x, int y) Node
+getTrafficNode(int x, int y) TrafficNode
+getRoadNetwork() Map
+printRoadNetwork() void
+findReachableNodes(int x, int y) Set
}
class EVController {
-Map<String, EV> evMap
-PathfindingVisualizer pathfinder
-TrafficManager trafficManager
+EVController()
+getEvMap() Map
+newEV(EVCreateRequest request) ResponseEntity
+canMoveToPosition(String evName, int x, int y) ResponseEntity
+getAllEVs() ResponseEntity
+startEV(String evName) ResponseEntity
+deleteEV(String evName) ResponseEntity
+updateEVPosition(String evName) ResponseEntity
+getEVStatus(String evName) ResponseEntity
-convertToPathNodes(long[] path) List
+getTrafficSignals() ResponseEntity
+changeTrafficSignals() ResponseEntity
}
class EV {
-String name
-int startX
-int startY
-int endX
-int endY
-int type
-int charge
-int chargingRate
-List<PathNode> path
+int currentPathIndex
-boolean moving
+Task task
-static final long MOVE_INTERVAL
+Queue<Task> taskQueue
+EV(int x, int y, int type, int charge, int chargingRate)
+getName() String
+setName(String name) void
+getStartX() int
+getStartY() int
+getEndX() int
+getEndY() int
+getType() int
+getCharge() int
+setPath(List<PathNode> path) void
+getPath() List<PathNode>
+getCurrentPathIndex() int
+getMoveInterval() long
+moveToNextPosition() void
+setEndLocation(int endX, int endY) void
+charge() void
+fullCharge() boolean
+getCurrentX() int
+getCurrentY() int
+isMoving() boolean
+setMoving(boolean moving) void
+getTask() void
}
class TrafficManager {
+static TrafficManager instance
-static final long SIGNAL_CHANGE_INTERVAL
+static ArrayList<TrafficNode> trafficLights
-static final ScheduledExecutorService scheduler
-static long nextSignalChangeTime
+TrafficManager()
+static getInstance() TrafficManager
+addTrafficNode(TrafficNode node) void
+updateSignals() void
+canMoveToPosition(EV ev, int targetX, int targetY) boolean
+startTrafficCycle() void
+static changeSignals() void
+shutdown() void
}
class TrafficNode {
-int signal
+int group
+TrafficNode(int x, int y, String type, int trafficType)
+changeSignal()
+isGreen()
+isRed()
+get_pair(TrafficNode currentNode)
}
class Node {
+int x
+int y
-boolean stalled
+List<Node> neighbors
+String type
+Node(int x, int y, String type)
+isStalled() boolean
+setStalled(boolean stalled) void
+equals(Object o) boolean
+hashCode() int
+toString() String
}
class Task {
-int start_x
-int start_y
-int end_x
-int end_y
-string task
+Task(string task, int start_x, int start_y, int end_x, int end_y)
+getTask() string
+getStartX() int
+getStartY() int
+getEndX() int
+getEndY() int
}
class PathController {
-final GameMap gameMap
-final PathfindingVisualizer pathfinder
+PathController()
+findPath(PathRequest request) List
-convertToPathNodes(long[] path) List
+getMapData() MapData
}
class PathfindingVisualizer {
-static boolean libraryLoaded
-GameMap map
-native findPathInNetwork(int startX, int startY, int endX, int endY, int[][] nodeCoords, int[][] neighborLists) long[]
+PathfindingVisualizer(GameMap map)
+runPathfindingSimulation() void
+findPath(int startX, int startY, int endX, int endY) long[]
-visualizePath(long[] path) void
}
class PathNode {
-int x
-int y
+getX()
+getY()
}
class RoadMapParser {
-Map<String, Node> nodes
-int rows
-int cols
+RoadMapParser()
+getRows() int
+getCols() int
+parseCSV(String filePath, String signalMapPath) void
-parseCoordinates(String cellValue) List
-getOrCreateNode(int x, int y, String type, int trafficType) Node
+printGraph() void
+getNode(int x, int y) Node
+getTrafficNode(int x, int y) TrafficNode
+getAllNodes() Collection
+pathExists(Node start, Node end) boolean
-dfs(Node current, Node end, Set<Node> visited) boolean
+findReachableNodes(Node start) Set
-dfsReachable(Node current, Set<Node> visited) void
+totalNodes() int
+main(String[] args) void
}
class TerminalSimulation {
-static final String ANSI_RED
-static final String ANSI_GREEN
-static final String ANSI_BLUE
-static final String ANSI_RESET
-GameMap gameMap
-TrafficManager trafficManager
-EVController evController
-volatile boolean running
+TerminalSimulation()
+start() void
-startEV(String evName) void
-convertToPathNodes(long[] path) List
-simulateEVMovement(String evName) void
-printMap() void
-clearScreen() void
+main(String[] args) void
}
class TaskAssigner {
-static TaskAssigner instance
+static Queue<Task> buffer
+TaskAssigner()
+static getInstance() TaskAssigner
+addTask(String string_task, int start_x, int end_x, int start_y, int end_y, Map<String, EV> evMap) void
+static assignTask() Task
+static giveTask(Map<String, EV> evMap) void
}
class Main {
+main(String[] args) void
}
class EVCreateRequest {
-String name
-int startX
-int startY
-int endX
-int endY
-int type
-int charge
-int chargingRate
+getName() String
+getStartX() int
+getStartY() int
+getEndX() int
+getEndY() int
+getType() int
+getCharge() int
+getChargingRate() int
}
class EVStatus {
-int charge
-int currentX
-int currentY
+EVStatus(int charge, int currentX, int currentY)
}
class TrafficSignalState {
+int x
+int y
+boolean isGreen
+TrafficSignalState(int x, int y, boolean isGreen)
}
class PathNode {
-int x
-int y
+PathNode(int x, int y)
+getX() int
+getY() int
}
class PathRequest {
-int startX
-int startY
-int endX
-int endY
+getStartX() int
+getStartY() int
+getEndX() int
+getEndY() int
+setStartX(int startX) void
+setStartY(int startY) void
+setEndX(int endX) void
+setEndY(int endY) void
}
class RoadNode {
-int x
-int y
-boolean oneWay
+RoadNode(int x, int y, boolean oneWay)
+getX() int
+getY() int
+isOneWay() boolean
}
class SevenApplication {
+static main(String[] args) void
}
class MapData {
-List<RoadNode> roads
+MapData(Map<String, Node> roadNetwork)
+getRoads() List<RoadNode>
}
EV o-- Task : has
EV o-- PathNode : contains >
EV ..> TaskAssigner : uses
EV *-- "1" Queue : contains taskQueue
EVController *-- "many" EV : manages
EVController o-- PathfindingVisualizer : uses
EVController o-- TrafficManager : uses
EVController ..> PathNode : creates
EVController ..> EVStatus : creates
EVController ..> EVCreateRequest : uses
EVController ..> TrafficSignalState : creates
GameMap *-- "many" Node : contains
GameMap o-- RoadMapParser : uses
GameMap ..> TrafficNode : creates
Node <|-- TrafficNode : extends
Node *-- "many" Node : neighbors
PathController o-- GameMap : uses
PathController o-- PathfindingVisualizer : uses
PathController ..> PathRequest : uses
PathController ..> PathNode : creates
PathController ..> MapData : creates
PathfindingVisualizer o-- GameMap : uses
PathfindingVisualizer ..> Node : uses
PathfindingVisualizer ..> PathNode : creates
RoadMapParser *-- "many" Node : contains
RoadMapParser ..> TrafficNode : creates
RoadMapParser ..> TrafficManager : uses
Task --o EV : assigned to
TaskAssigner *-- "many" Task : manages
TaskAssigner ..> EV : assigns tasks to
TerminalSimulation o-- GameMap : uses
TerminalSimulation o-- TrafficManager : uses
TerminalSimulation o-- EVController : uses
TerminalSimulation ..> PathNode : creates
TerminalSimulation ..> EV : manages
TrafficNode ..> GameMap : uses
TrafficManager *-- "many" TrafficNode : manages
TrafficManager o-- GameMap : uses
TrafficManager ..> EV : controls movement
- Java Development Kit (JDK) 17 or higher
- Apache Maven for dependency management
- Modern web browser (Chrome, Firefox, Safari)
- Operating System: Windows, macOS, or Linux
The project uses a JNI (Java Native Interface) approach with a C++ Dijkstra implementation:
- Locate
dijkstra_jni.dll
inVehicle-Simulation/lib
- Add the DLL directory to system PATH
- Open System Properties > Advanced > Environment Variables
- Append DLL directory path to PATH variable
- Set
LD_LIBRARY_PATH
:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/native/lib
# Clone the repository
git clone https://github.com/prakrititz/Vehicle-Simulation.git
cd Vehicle-Simulation
## Method 1. Build
# Build the project
mvn clean install
# Run the application
mvn spring-boot:run
## Method 2. Or run the .jar file after adding dll to the path
mvn clean package
java -jar ./target/seven-0.0.1-SNAPSHOT.jar
# Build the Docker Image
# Run the following command to build your Docker image:
docker build -t vehicle-simulator .
# Run the Docker Container
# Run your application in a Docker container:
docker run -p 8080:8080 vehicle-simulator
# This maps port 8080 of your application to port 8080 of your host machine.
# Visit http://localhost:8080 in your browser
- Simulation Accuracy: 95% traffic flow prediction
- Real-time Processing: Sub-millisecond computational latency
- Scalability: Supports up to 1000 concurrent vehicle simulations
Contributions are welcome! Please read our contributing guidelines and code of conduct.
- Dijkstra Algorithm Implementation
- Spring Boot Community
- Phaser.js Visualization Library
Encapsulation ensures that the internal state of objects is hidden and only accessible through defined interfaces (getters and setters). In this project:
- The EV class encapsulates details like charge level, current position, and path, preventing unintended behavior by restricting direct modifications.
- The GameMap class encapsulates the entire road network, exposing methods like
isWalkable
,getRoadNode
, andgetObstacleMap
, providing controlled access to map data.
By encapsulating data, developers can focus on using high-level methods without worrying about the details, simplifying debugging and extending functionality.
Inheritance promotes code reuse and logical hierarchy by allowing specialized classes to derive functionality from base classes.
- The Node class acts as a base class representing a generic point in the road network. Specialized classes like TrafficNode inherit from it to add traffic light management.
- The EV class is extended by NPCVehicle to model autonomous behaviors. For example:
- EV handles basic movement and task assignment.
- NPCVehicle introduces randomness in destination selection and re-routing logic via the overridden
changeEnd()
method.
Polymorphism allows different objects to be treated as instances of their parent class, enabling dynamic method dispatch.
-
Nodes and Traffic Nodes:
- The GameMap interacts seamlessly with TrafficNode objects due to polymorphism.
- Example:
getTrafficNode()
in RoadMapParser dynamically checks node types, allowing flexible interactions with both Node and TrafficNode instances.
-
EV and NPCVehicle:
- The EVController manages EV objects but also handles NPCVehicle instances due to their shared parent class.
- Example: When
simulateEVMovement
is called, NPCVehicle's overriddenchangeEnd()
ensures specific behaviors without needing separate logic.
Abstraction simplifies complex processes:
- PathfindingVisualizer abstracts JNI-based native pathfinding logic, exposing a high-level
findPath()
method while hiding the C++ implementation. - TrafficManager abstracts signal handling and movement constraints, offering methods like
canMoveToPosition
without exposing signal state complexities.
The GameMap, TrafficManager, and TaskAssigner use the Singleton pattern to ensure only one instance of each exists. This centralization avoids inconsistencies and ensures shared data access.
Threading is vital for real-time simulation. Hereβs how itβs utilized:
- Each EV simulation runs in its own thread, allowing independent movement.
- Example: In EVController,
simulateEVMovement
spawns threads for each EV, ensuring one EV waiting at a signal doesn't block others.
- Threads periodically update the map visualization and EV statuses, providing dynamic feedback for users.
- Shared resources (e.g., evMap) require thread-safety mechanisms like locks or synchronized blocks to prevent race conditions.
- TaskAssigner distributes tasks among EVs in a thread-safe manner, with threads polling for tasks from a shared buffer.
- Represents a generic graph node with attributes like coordinates, neighbors, and stalled status.
- Implements
equals()
andhashCode()
based on coordinates for efficient lookups.
- Inherits from Node and adds traffic-specific functionality like signal states and traffic types.
- Integrated into the network via polymorphism, dynamically casting Node objects to TrafficNode as needed.
- Polymorphism ensures TrafficNode behaves as a Node in pathfinding but introduces signal-specific logic when required.
- Example:
- TrafficNode instances are managed by TrafficManager for signal control.
- Standard nodes act as simple graph points in algorithms, minimizing overhead.
- Node: Generic road intersection.
- TrafficNode: Intersection with a traffic light influencing vehicle behavior.
All members of the team have contributed equally to all aspects of the project, adopting a collaborative approach rather than dividing tasks individually. Given the scale and complexity of the project, it became clear that assigning isolated responsibilities would not be effective. The interconnected nature of components like pathfinding, traffic management, EV simulation, and frontend visualization required every member to have a holistic understanding of the entire system.
To ensure this, the team worked together on:
-
Pathfinding and JNI Integration:
- Jointly implementing and optimizing the native pathfinding logic.
- Collaboratively managing JNI data conversion between Java and C++.
-
Game Map and Parsing:
- Parsing road network data, building the GameMap, and ensuring accurate connectivity through team discussions and development sessions.
-
Traffic Management:
- Designing traffic light cycles and movement constraints collectively, ensuring everyone understood the intricate dependencies.
-
EV Simulation and Controller:
- Working as a team to define EV behaviors, movement logic, and REST API integration, avoiding siloed knowledge.
-
Task Assignment and Buffering:
- Co-developing the task queue and task prioritization logic, ensuring fair distribution of knowledge and effort.
-
Frontend/Visualization:
- Collaboratively creating the interface for real-time updates and visualization, reinforcing a shared understanding of the output.
This approach ensured that all team members were equipped to debug, extend, and maintain any part of the project, highlighting the importance of shared responsibility for a project of this scale.
This project highlights strong OOP principles, threading, and modular design. Inheritance and polymorphism enable seamless integration of components like nodes, traffic nodes, EVs, and NPCs. Threading ensures real-time simulation, while encapsulation and abstraction simplify development and maintenance. The proposed work distribution promotes balanced responsibilities and efficient collaboration.