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
7 changes: 5 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:22.04
FROM ubuntu:25.10

LABEL maintainer="Felix Renzikowski <st166260@stud.uni-stuttgart.de>"

Expand All @@ -16,7 +16,10 @@ RUN apt-get update && apt-get install -y \
qtbase5-dev \
qt5-qmake \
libgtest-dev \
libopencv-dev
libopencv-dev \
gprbuild \
ninja-build \
gnat

RUN mkdir /usr/src/gtest/build
RUN cd /usr/src/gtest/build && cmake .. && make && cd lib && cp *.a /usr/lib
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_test_only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y qtcreator qtbase5-dev qt5-qmake cmake ninja-build make libgtest-dev libopencv-dev
sudo apt-get install -y qtcreator qtbase5-dev qt5-qmake cmake ninja-build make libgtest-dev libopencv-dev gprbuild gnat
sudo mkdir /usr/src/gtest/build
sudo cd /usr/src/gtest/build && sudo cmake .. && sudo make && sudo cd lib && sudo cp *.a /usr/lib
sudo rm -r /usr/src/gtest/build
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y qtcreator qtbase5-dev texlive-full qt5-qmake doxygen build-essential
sudo apt-get install -y cmake graphviz ninja-build make libgtest-dev libopencv-dev
sudo apt-get install -y cmake graphviz ninja-build make libgtest-dev libopencv-dev gprbuild gnat
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build && sudo cmake .. && sudo make && cd lib && sudo cp *.a /usr/lib
sudo rm -r /usr/src/gtest/build
sudo apt upgrade -y

- name: Configure and Build CMake
run: |
cmake -GNinja -S ${{github.workspace}} -B ${{github.workspace}}/build
cmake --build ${{github.workspace}}/build
cmake -GNinja -S ${{github.workspace}} -B ${{github.workspace}}/build -DWITH_DOCS=ON -DWITH_PAPER=ON
cmake --build ${{github.workspace}}/build

- name: Test
working-directory: ${{github.workspace}}/build
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@

# Custom
cmake-build-debug/
build/
Core/Pathfinder/ada_backend/lib
Core/Pathfinder/ada_backend/obj
.idea/
Paper/out
*.log
Expand Down
20 changes: 20 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Pathfinding (GUI)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/Pathfinding_Bench_Program",
"args": ["--gui"],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{ "description": "Enable pretty-printing", "text": "-enable-pretty-printing", "ignoreFailures": true }
],
"preLaunchTask": "CMake: build"
}
]
}
61 changes: 34 additions & 27 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ project(
LANGUAGES C CXX ASM
)

option(WITH_DOCS "Build documentation" OFF)
option(WITH_PAPER "Build paper output" OFF)

enable_testing()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -35,33 +38,37 @@ add_subdirectory(Core/GUI)
add_executable(Pathfinding_Bench_Program Core/main.cpp)
target_link_libraries(Pathfinding_Bench_Program Application GridGenerator Pathfinder GUI RunInterface GUI_widgets)

# doxygen documentation
find_package(Doxygen)

if (DOXYGEN_FOUND)
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
add_custom_command(TARGET Pathfinding_Bench_Program POST_BUILD
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} > /dev/null 2>&1
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
)

find_program(MAKE_EXECUTABLE make)
if (MAKE_EXECUTABLE)
add_custom_command(TARGET Pathfinding_Bench_Program POST_BUILD
COMMAND ${MAKE_EXECUTABLE} > /dev/null 2>&1
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/latex
COMMENT "Generating PDF documentation"
)
else (MAKE_EXECUTABLE)
message("Could not find 'make' command for generating PDF documentation.")
endif ()
else (DOXYGEN_FOUND)
message("Doxygen needs to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)
if(WITH_DOCS)
# doxygen documentation
find_package(Doxygen)

if (DOXYGEN_FOUND)
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
add_custom_command(TARGET Pathfinding_Bench_Program POST_BUILD
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} > /dev/null 2>&1
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
)
else (DOXYGEN_FOUND)
message("Doxygen needs to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)
endif(WITH_DOCS)

if(WITH_PAPER)
find_program(MAKE_EXECUTABLE make)
if (MAKE_EXECUTABLE)
add_custom_command(TARGET Pathfinding_Bench_Program POST_BUILD
COMMAND ${MAKE_EXECUTABLE} > /dev/null 2>&1
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/latex
COMMENT "Generating PDF documentation"
)
else (MAKE_EXECUTABLE)
message("Could not find 'make' command for generating PDF documentation.")
endif ()
endif(WITH_PAPER)

# set up testing
find_package(GTest)
Expand Down
42 changes: 38 additions & 4 deletions Core/Pathfinder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,41 @@
# Glob for the inc and src directories in each module
file(GLOB SOURCE_FILES "src/*.cpp")
find_program(GPRBUILD_EXECUTABLE NAMES gprbuild gnatmake)
if(NOT GPRBUILD_EXECUTABLE)
message(FATAL_ERROR "gprbuild not found; please install GNAT or ensure gprbuild is on PATH")
endif()

include(ExternalProject)

set(ADA_OUTPUT_LIB "${CMAKE_CURRENT_SOURCE_DIR}/ada_backend/lib/libpathfinding_ada.so")
set(ADA_PROJECT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ada_backend/libpathfinding_ada.gpr")

add_custom_command(
OUTPUT "${ADA_OUTPUT_LIB}"
COMMAND gprbuild -p -P "${ADA_PROJECT_FILE}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Building Ada library via gprbuild"
VERBATIM
)

add_custom_target(Pathfinder_Ada_Proj ALL
DEPENDS "${ADA_OUTPUT_LIB}"
)

add_library(Pathfinder_C_ABI STATIC ${CMAKE_CURRENT_SOURCE_DIR}/c_abi/src/pathfinding_c_inf.cpp)
target_include_directories(Pathfinder_C_ABI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/c_abi/inc)

# Add each module as a library and set its dependencies
add_library(Pathfinder_Ada SHARED IMPORTED GLOBAL)
set_target_properties(Pathfinder_Ada PROPERTIES
IMPORTED_LOCATION "${ADA_OUTPUT_LIB}"
)

add_dependencies(Pathfinder_Ada Pathfinder_Ada_Proj Pathfinder_C_ABI)

target_link_libraries(Pathfinder_Ada INTERFACE Pathfinder_C_ABI)
add_dependencies(Pathfinder_Ada Pathfinder_Ada_Proj Pathfinder_C_ABI)
target_link_libraries(Pathfinder_C_ABI PRIVATE GridGenerator)

file(GLOB SOURCE_FILES "src/*.cpp")
add_library(Pathfinder ${SOURCE_FILES})
target_include_directories(Pathfinder PUBLIC inc)
target_link_libraries(Pathfinder GridGenerator)
target_link_libraries(Pathfinder GridGenerator Pathfinder_Ada Pathfinder_C_ABI)

10 changes: 10 additions & 0 deletions Core/Pathfinder/ada_backend/libpathfinding_ada.gpr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
library project libpathfinding_ada is
for Source_Dirs use ("src");
for Library_Dir use "lib";
for Object_Dir use "obj";
for Library_Name use "pathfinding_ada";
for Library_Kind use "dynamic";
package Compiler is
for Default_Switches ("Ada") use ("-g", "-O0");
end Compiler;
end libpathfinding_ada;
83 changes: 83 additions & 0 deletions Core/Pathfinder/ada_backend/src/a_star.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
with Pathfinder_C_Inf; use Pathfinder_C_Inf;
with Pathfinder_Common; use Pathfinder_Common;
with Interfaces.C; use Interfaces.C;
with Interfaces; use Interfaces;
with Ada.Text_IO; use Ada.Text_IO;

package body a_star is
procedure nextStep
(grid : Grid_Handle;
current_coord_x : Pathfinder_C_Inf.Grid_Idx;
current_coord_y : Pathfinder_C_Inf.Grid_Idx;
end_coord_x : Pathfinder_C_Inf.Grid_Idx;
end_coord_y : Pathfinder_C_Inf.Grid_Idx;
queue : Cell_Queue_Handle)
with SPARK_Mode => On
is
current_coord : Pathfinder_C_Inf.Grid_Coord :=
Pathfinder_C_Inf.Grid_Coord'(current_coord_x, current_coord_y);
end_coord : Pathfinder_C_Inf.Grid_Coord :=
Pathfinder_C_Inf.Grid_Coord'(end_coord_x, end_coord_y);
neighbors : Neighbors_Array :=
get_neighbors_from_coord (grid, current_coord.x, current_coord.y);
current_costs : Cell_Cost :=
get_cell_cost (grid, current_coord.x, current_coord.y);
current_g : Safe_Cost := current_costs.gCost;
neighbor_coord : Grid_Coord;
neighbor_costs : Cell_Cost;
neighbor_state : Cell_State;
neighbor_g_from_current : C_Double;
begin
for I in GridCoordArray'Range loop
neighbor_coord := neighbors.coords (I);

-- skip empty sentinel entries (wrapper pads remaining slots with U32_MAX)
exit when neighbor_coord.x = -1 and neighbor_coord.y = -1;
neighbor_g_from_current :=
current_g + Octile_Distance (neighbor_coord, current_coord);

neighbor_state :=
get_cell_state (grid, neighbor_coord.x, neighbor_coord.y);

if neighbor_state = CELL_OPEN then
set_cell_costs
(grid,
neighbor_coord.x,
neighbor_coord.y,
neighbor_g_from_current,
Absolute_Distance (neighbor_coord, end_coord));
set_parent_cell_pointer
(grid,
neighbor_coord.x,
neighbor_coord.y,
current_coord.x,
current_coord.y);
mark_cell_visited (grid, neighbor_coord.x, neighbor_coord.y);
push_to_cell_queue (queue, neighbor_coord.x, neighbor_coord.y);
increment_visited_cell_count (grid);

elsif neighbor_state = CELL_VISITED then
neighbor_costs :=
get_cell_cost (grid, neighbor_coord.x, neighbor_coord.y);
if neighbor_costs.gCost > neighbor_g_from_current then
-- preserve previous h-cost
set_cell_costs
(grid,
neighbor_coord.x,
neighbor_coord.y,
neighbor_g_from_current,
neighbor_costs.hCost);
set_parent_cell_pointer
(grid,
neighbor_coord.x,
neighbor_coord.y,
current_coord.x,
current_coord.y);
push_to_cell_queue (queue, neighbor_coord.x, neighbor_coord.y);
increment_visited_cell_count (grid);
end if;
end if;
end loop;
end nextStep;

end a_star;
18 changes: 18 additions & 0 deletions Core/Pathfinder/ada_backend/src/a_star.ads
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
with Pathfinder_C_Inf; use Pathfinder_C_Inf;

package a_star is
procedure nextStep
(grid : Grid_Handle;
current_coord_x : Pathfinder_C_Inf.Grid_Idx;
current_coord_y : Pathfinder_C_Inf.Grid_Idx;
end_coord_x : Pathfinder_C_Inf.Grid_Idx;
end_coord_y : Pathfinder_C_Inf.Grid_Idx;
queue : Cell_Queue_Handle)
with
Convention => C,
SPARK_Mode => On,
Export => True,
External_Name => "ada_astar_next_step",
Global => null;

end a_star;
79 changes: 79 additions & 0 deletions Core/Pathfinder/ada_backend/src/dijkstra.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
with Pathfinder_C_Inf; use Pathfinder_C_Inf;
with Pathfinder_Common; use Pathfinder_Common;
with Interfaces.C; use Interfaces.C;
with Interfaces; use Interfaces;
with Ada.Text_IO; use Ada.Text_IO;

package body dijkstra is
procedure nextStep
(grid : Grid_Handle;
current_coord_x : Pathfinder_C_Inf.Grid_Idx;
current_coord_y : Pathfinder_C_Inf.Grid_Idx;
queue : Cell_Queue_Handle)
with SPARK_Mode => On
is
current_coord : Pathfinder_C_Inf.Grid_Coord :=
(x => current_coord_x, y => current_coord_y);
neighbors : constant Neighbors_Array :=
get_neighbors_from_coord (grid, current_coord.x, current_coord.y);
current_costs : constant Cell_Cost :=
get_cell_cost (grid, current_coord.x, current_coord.y);
current_g : constant Pathfinder_C_Inf.Safe_Cost :=
current_costs.gCost;
neighbor_coord : Grid_Coord;
neighbor_costs : Cell_Cost;
neighbor_state : Cell_State;
neighbor_g_from_current : Pathfinder_C_Inf.C_Double;
begin
for I in GridCoordArray'Range loop
neighbor_coord := neighbors.coords (I);

-- skip empty sentinel entries (wrapper pads remaining slots with U32_MAX)
exit when neighbor_coord.x = -1 and neighbor_coord.y = -1;
neighbor_g_from_current :=
current_g + Octile_Distance (neighbor_coord, current_coord);

neighbor_state :=
get_cell_state (grid, neighbor_coord.x, neighbor_coord.y);

if neighbor_state = CELL_OPEN then
set_cell_costs
(grid,
neighbor_coord.x,
neighbor_coord.y,
neighbor_g_from_current,
0.0);
set_parent_cell_pointer
(grid,
neighbor_coord.x,
neighbor_coord.y,
current_coord.x,
current_coord.y);
mark_cell_visited (grid, neighbor_coord.x, neighbor_coord.y);
push_to_cell_queue (queue, neighbor_coord.x, neighbor_coord.y);
increment_visited_cell_count (grid);

elsif neighbor_state = CELL_VISITED then
neighbor_costs :=
get_cell_cost (grid, neighbor_coord.x, neighbor_coord.y);
if neighbor_costs.gCost > neighbor_g_from_current then
set_cell_costs
(grid,
neighbor_coord.x,
neighbor_coord.y,
neighbor_g_from_current,
0.0);
set_parent_cell_pointer
(grid,
neighbor_coord.x,
neighbor_coord.y,
current_coord.x,
current_coord.y);
push_to_cell_queue (queue, neighbor_coord.x, neighbor_coord.y);
increment_visited_cell_count (grid);
end if;
end if;
end loop;
end nextStep;

end dijkstra;
Loading