Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@

A tool for visualizing numerous pathfinding algorithms in two dimensions.

This project involves minimal implementations of the popular planning algorithms, including both graph-based and sampling-based planners. We provide an easy-to-use GUI to control the animation process and explore different planner configurations. This is an ongoing work and current implementation of the project only involves four search-based planning algorithms: BFS, DFS, DIJKSTRA and A-Star and two sampling-based planners: RRT and RRT*. The project extensively uses SFML, ImGui and Modern C++ features such as smart pointers, lamda expressions along with multi-threading concepts.
This project involves minimal implementations of the popular planning algorithms, including both graph-based and sampling-based planners. We provide an easy-to-use GUI to control the animation process and explore different planner configurations. Current implementation of the project involves four search-based planning algorithms: BFS, DFS, DIJKSTRA and A-Star and two sampling-based planners: RRT and RRT*. The project extensively uses SFML, ImGui and Modern C++ features such as smart pointers, lamda expressions along with multi-threading concepts.

![](figures/img0.png)

## How to use

- to place/remove obstacle cells (`left-CLICKED`)
- to change starting cell (`left-SHIFT + left-CLICKED`)
- to change end cell (`left-CTRL + left-CLICKED`)

## Dependencies

* cmake >= 3.14
Expand Down
3 changes: 2 additions & 1 deletion dependencies/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ add_subdirectory(sfml)
FetchContent_Declare(
imgui
GIT_REPOSITORY https://github.com/ocornut/imgui
GIT_TAG 55d35d8387c15bf0cfd71861df67af8cfbda7456
# GIT_TAG 55d35d8387c15bf0cfd71861df67af8cfbda7456
GIT_TAG 719d9313041b85227a3e6deb289a313819aaeab3 # latest commit of docking-branch
)

FetchContent_Declare(
Expand Down
Binary file modified figures/img0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 15 additions & 2 deletions include/Game.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ enum SAMPLING_BASED_PLANNERS_IDS { RRT, RRT_STAR };
class Game {
public:
// Constructors
Game(sf::RenderWindow* window);
Game(sf::RenderWindow* window, sf::RenderTexture* render_texture);

// Destructors
virtual ~Game();
Expand All @@ -36,17 +36,30 @@ class Game {
void update();
void render();
void initGuiTheme();
void renderGui();
void renderNewPlannerMenu();
void renderRunMenu(ImGuiIO& io);
void setGraphBasedPlanner(const int id);
void setSamplingBasedPlanner(const int id);
void showHowToUseWindow();
void showAboutWindow();

private:
sf::RenderWindow* window_;
sf::RenderTexture* render_texture_;
sf::Vector2f view_move_xy_;
ImVec2 mouse_pos_in_canvas_;
sf::Event ev_;
sf::Clock dtClock_;
float dt_;
std::stack<std::unique_ptr<State>> states_;
std::string curr_planner_;
std::shared_ptr<gui::LoggerPanel> logger_panel_;
bool disable_run_;
bool show_how_to_use_window_{true};
bool show_about_window_{true};
bool show_control_panel_{true};
bool show_console_{true};
bool show_stats_panel_{true};
};

} // namespace path_finding_visualizer
134 changes: 134 additions & 0 deletions include/Gui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#pragma once

#include <imgui-SFML.h>
#include <imgui.h>

namespace path_finding_visualizer {
namespace gui {

class LoggerPanel {
public:
LoggerPanel() {
AutoScroll = true;
clear();
}

void clear() {
Buf.clear();
LineOffsets.clear();
LineOffsets.push_back(0);
}

void render(const char* title) {
if (!ImGui::Begin(title)) {
ImGui::End();
return;
}

ImGui::BeginChild("scrolling", ImVec2(0, 0), false,
ImGuiWindowFlags_HorizontalScrollbar);

ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
const char* buf = Buf.begin();
const char* buf_end = Buf.end();
{
ImGuiListClipper clipper;
clipper.Begin(LineOffsets.Size);
while (clipper.Step()) {
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd;
line_no++) {
const char* line_start = buf + LineOffsets[line_no];
const char* line_end = (line_no + 1 < LineOffsets.Size)
? (buf + LineOffsets[line_no + 1] - 1)
: buf_end;
ImGui::TextUnformatted(line_start, line_end);
}
}
clipper.End();
}
ImGui::PopStyleVar();

if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);

ImGui::EndChild();
ImGui::End();
}

void info(const std::string& msg) { AddLog("[INFO] %s\n", msg.c_str()); }

private:
ImGuiTextBuffer Buf;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with
// AddLog() calls.
bool AutoScroll; // Keep scrolling if already at the bottom.

void AddLog(const char* fmt, ...) IM_FMTARGS(2) {
int old_size = Buf.size();
va_list args;
va_start(args, fmt);
Buf.appendfv(fmt, args);
va_end(args);
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n') LineOffsets.push_back(old_size + 1);
}
};

// Helper to display a little (?) mark which shows a tooltip when hovered.
// In your own code you may want to display an actual icon if you are using a
// merged icon fonts (see docs/FONTS.md)
inline void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}

inline bool inputInt(const std::string& label, int* val, const int& min_val,
const int& max_val, const int& step = 1,
const int& step_fast = 100,
const std::string& help_marker = "",
ImGuiInputTextFlags flags = 0) {
flags |= ImGuiInputTextFlags_EnterReturnsTrue;
bool is_active = ImGui::InputInt(label.c_str(), val, step, step_fast, flags);
if (!help_marker.empty()) {
ImGui::SameLine();
HelpMarker(help_marker.c_str());
}
if (is_active) {
if (*val < min_val)
*val = min_val;
else if (*val > max_val)
*val = max_val;
}
return is_active;
}

inline bool inputDouble(const std::string& label, double* val,
const double& min_val, const double& max_val,
const double& step = 0.0, const double& step_fast = 0.0,
const std::string& help_marker = "",
const char* format = "%.6f",
ImGuiInputTextFlags flags = 0) {
flags |= ImGuiInputTextFlags_EnterReturnsTrue;
bool is_active =
ImGui::InputDouble(label.c_str(), val, step, step_fast, format, flags);
if (!help_marker.empty()) {
ImGui::SameLine();
HelpMarker(help_marker.c_str());
}
if (is_active) {
if (*val < min_val)
*val = min_val;
else if (*val > max_val)
*val = max_val;
}
return is_active;
}

} // namespace gui
} // namespace path_finding_visualizer
27 changes: 14 additions & 13 deletions include/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <stack>
#include <string>
#include <vector>

#include "Gui.h"

/*
State Base Class
*/
Expand All @@ -19,31 +22,29 @@ namespace path_finding_visualizer {
class State {
private:
protected:
std::stack<std::unique_ptr<State>> &states_;

sf::RenderWindow *window_;
sf::Vector2i mousePositionWindow_;
bool quit_;
std::shared_ptr<gui::LoggerPanel> logger_panel_;
sf::Vector2f mousePositionWindow_;
bool is_reset_;
bool is_running_;

public:
// Constructor
State(sf::RenderWindow *window, std::stack<std::unique_ptr<State>> &states);
State(std::shared_ptr<gui::LoggerPanel> logger_panel);

// Destructor
virtual ~State();

// Accessors
const bool getQuit() const;
void setReset(bool is_reset) { is_reset_ = is_reset; }
void setRunning(bool is_running) { is_running_ = is_running; }

// Functions
virtual void checkForQuit();
virtual void updateMousePosition();
void updateMousePosition(const ImVec2 &mousePos);

// virtual functions
virtual void endState() = 0;
virtual void updateKeybinds() = 0;
virtual void update(const float &dt) = 0;
virtual void render() = 0;
virtual void update(const float &dt, const ImVec2 &mousePos) = 0;
virtual void renderConfig() = 0;
virtual void renderScene(sf::RenderTexture &render_texture) = 0;
};

} // namespace path_finding_visualizer
9 changes: 5 additions & 4 deletions include/States/Algorithms/GraphBased/ASTAR/ASTAR.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ struct MinimumDistanceASTAR {
class ASTAR : public BFS {
public:
// Constructor
ASTAR(sf::RenderWindow *window, std::stack<std::unique_ptr<State>> &states);
ASTAR(std::shared_ptr<gui::LoggerPanel> logger_panel);

// Destructor
virtual ~ASTAR();

// Overriden functions
virtual void initAlgorithm() override;
virtual void solveConcurrently(
std::shared_ptr<Node> nodeStart, std::shared_ptr<Node> nodeEnd,
std::shared_ptr<MessageQueue<bool>> message_queue) override;

// override main update function
virtual void updatePlanner(bool &solved, Node &start_node,
Node &end_node) override;

protected:
// ASTAR related
Expand Down
11 changes: 5 additions & 6 deletions include/States/Algorithms/GraphBased/BFS/BFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace graph_based {
class BFS : public GraphBased {
public:
// Constructor
BFS(sf::RenderWindow *window, std::stack<std::unique_ptr<State>> &states);
BFS(std::shared_ptr<gui::LoggerPanel> logger_panel);

// Destructor
virtual ~BFS();
Expand All @@ -23,13 +23,12 @@ class BFS : public GraphBased {
virtual void updateNodes() override;

// override render functions
virtual void renderNodes() override;
virtual void renderNodes(sf::RenderTexture &render_texture) override;
virtual void renderParametersGui() override;

// BFS algorithm function
virtual void solveConcurrently(
std::shared_ptr<Node> nodeStart, std::shared_ptr<Node> nodeEnd,
std::shared_ptr<MessageQueue<bool>> message_queue) override;
// override main update function
virtual void updatePlanner(bool &solved, Node &start_node,
Node &end_node) override;

private:
// BFS related
Expand Down
9 changes: 4 additions & 5 deletions include/States/Algorithms/GraphBased/DFS/DFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@ namespace graph_based {
class DFS : public BFS {
public:
// Constructor
DFS(sf::RenderWindow *window, std::stack<std::unique_ptr<State>> &states);
DFS(std::shared_ptr<gui::LoggerPanel> logger_panel);

// Destructor
virtual ~DFS();

// override initialization Functions
void initAlgorithm() override;

// DFS algorithm function
void solveConcurrently(
std::shared_ptr<Node> nodeStart, std::shared_ptr<Node> nodeEnd,
std::shared_ptr<MessageQueue<bool>> message_queue) override;
// override main update function
virtual void updatePlanner(bool &solved, Node &start_node,
Node &end_node) override;

private:
// DFS related
Expand Down
10 changes: 5 additions & 5 deletions include/States/Algorithms/GraphBased/DIJKSTRA/DIJKSTRA.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ struct MinimumDistanceDIJKSTRA {
class DIJKSTRA : public BFS {
public:
// Constructor
DIJKSTRA(sf::RenderWindow *window,
std::stack<std::unique_ptr<State>> &states);
DIJKSTRA(std::shared_ptr<gui::LoggerPanel> logger_panel);

// Destructor
virtual ~DIJKSTRA();

// Overriden functions
virtual void initAlgorithm() override;
void solveConcurrently(
std::shared_ptr<Node> nodeStart, std::shared_ptr<Node> nodeEnd,
std::shared_ptr<MessageQueue<bool>> message_queue) override;

// override main update function
virtual void updatePlanner(bool &solved, Node &start_node,
Node &end_node) override;

protected:
// DIJKSTRA related
Expand Down
Loading