diff --git a/.github/workflows/release-appimage.yaml b/.github/workflows/release-appimage.yaml new file mode 100644 index 0000000..4411d73 --- /dev/null +++ b/.github/workflows/release-appimage.yaml @@ -0,0 +1,59 @@ +name: Release AppImage + +on: + workflow_dispatch: # Allows manual triggering + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + build-appimage: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Cache apt packages + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: git cmake liblz4-dev libzstd-dev libpcl-dev libboost-all-dev + version: 1.0 + + - name: Configure + run: cmake cloudini_lib -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=OFF + + - name: Build + run: make -j$(nproc) install DESTDIR=AppDir + + - name: Build AppImage + uses: AppImageCrafters/build-appimage-action@master + env: + UPDATE_INFO: gh-releases-zsync|AppImageCrafters|cloudini_rosbag_converter|latest|*x86_64.AppImage.zsync + with: + recipe: AppImageBuilder.yml + + - name: Get version from tag + id: get_version + run: | + if [ "${{ github.event_name }}" = "push" ]; then + echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + else + echo "VERSION=manual-build" >> $GITHUB_OUTPUT + fi + + - name: Create Release + uses: softprops/action-gh-release@v1 + if: github.event_name == 'push' # Only create release for tag pushes + with: + name: Release ${{ steps.get_version.outputs.VERSION }} + files: | + *.AppImage* + draft: false + prerelease: false + + - name: Upload Artifacts + if: github.event_name == 'workflow_dispatch' # Only upload artifacts for manual runs + uses: actions/upload-artifact@v4 + with: + name: AppImage-manual-build + path: '*.AppImage*' diff --git a/.github/workflows/ubuntu-build.yaml b/.github/workflows/ubuntu-build.yaml new file mode 100644 index 0000000..d0fb540 --- /dev/null +++ b/.github/workflows/ubuntu-build.yaml @@ -0,0 +1,44 @@ +name: Ubuntu Build & Test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Cache apt packages + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: git cmake libpcl-dev liblz4-dev libzstd-dev libgtest-dev libboost-all-dev + version: 1.0 + + - name: Cache CMake files + uses: actions/cache@v4 + with: + path: | + ~/.cache/cmake + build + key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }} + restore-keys: | + ${{ runner.os }}-cmake- + + - name: Configure + run: | + mkdir -p build + cd build + cmake ../cloudini_lib -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON + + - name: Build + working-directory: build + run: make -j$(nproc) + + - name: Run tests + working-directory: build + run: ctest --output-on-failure diff --git a/.vscode/settings.json b/.vscode/settings.json index 8374ca0..7ae99f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -90,7 +90,8 @@ "qmessagebox": "cpp", "qapplication": "cpp", "locale": "cpp", - "filesystem": "cpp" + "filesystem": "cpp", + "*.tcc": "cpp" }, "python.autoComplete.extraPaths": [ "/opt/ros/humble/lib/python3.10/site-packages", @@ -100,4 +101,4 @@ "/opt/ros/humble/lib/python3.10/site-packages", "/opt/ros/humble/local/lib/python3.10/dist-packages" ], -} +} \ No newline at end of file diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 0000000..e201576 --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,53 @@ +version: 1 +script: + # Remove any old AppDir + - rm -rf AppDir || true + # Make sure you have a clean AppDir + - mkdir -p AppDir + +AppDir: + path: AppDir + + app_info: + id: com.github.cloudini + name: cloudini + icon: auto + version: latest + exec: usr/bin/cloudini_rosbag_converter + exec_args: $@ + + apt: + arch: amd64 + sources: + - sourceline: 'deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse' + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C' + + include: [] + exclude: [] + + files: + include: [] + exclude: + - usr/share/man + - usr/share/doc + + test: + fedora-30: + image: appimagecrafters/tests-env:fedora-30 + command: ./AppRun + debian-stable: + image: appimagecrafters/tests-env:debian-stable + command: ./AppRun + archlinux-latest: + image: appimagecrafters/tests-env:archlinux-latest + command: ./AppRun + centos-7: + image: appimagecrafters/tests-env:centos-7 + command: ./AppRun + ubuntu-xenial: + image: appimagecrafters/tests-env:ubuntu-xenial + command: ./AppRun + +AppImage: + arch: x86_64 + update-information: guess diff --git a/cloudini_lib/CMakeLists.txt b/cloudini_lib/CMakeLists.txt index 127f16b..dc44979 100644 --- a/cloudini_lib/CMakeLists.txt +++ b/cloudini_lib/CMakeLists.txt @@ -32,7 +32,6 @@ message(STATUS "LZ4_INCLUDE_DIR: ${LZ4_INCLUDE_DIR}") message(STATUS "LZ4_LIBRARY: ${LZ4_LIBRARY}") - ################################################################################## # ---- Trick to pass an absolute path to C++ code ---- @@ -85,12 +84,14 @@ target_include_directories(cloudini_lib PRIVATE $ $ + $ ) target_link_libraries(cloudini_lib PRIVATE ${LZ4_LIBRARY} ${ZSTD_LIBRARY} + ${DRACO_LIBRARY} PUBLIC ${PCL_LIBRARIES} ) diff --git a/cloudini_lib/benchmarks/CMakeLists.txt b/cloudini_lib/benchmarks/CMakeLists.txt index e2ae73e..9969dc8 100644 --- a/cloudini_lib/benchmarks/CMakeLists.txt +++ b/cloudini_lib/benchmarks/CMakeLists.txt @@ -13,21 +13,35 @@ else() endif() +find_package(Draco QUIET) if(PCL_FOUND) message(STATUS "PCL found, using system include") - add_executable(pcd_benchmark pcd_benchmark.cpp ) + add_executable(pcd_benchmark pcd_benchmark.cpp) - target_include_directories(pcd_benchmark PRIVATE ${PCL_INCLUDE_DIRS}}) + target_include_directories(pcd_benchmark + PRIVATE + ${PCL_INCLUDE_DIRS} + ${DRACO_INCLUDE_DIRS} + ) - target_link_libraries(pcd_benchmark + target_link_libraries(pcd_benchmark PRIVATE cloudini_lib benchmark data_path ${PCL_LIBRARIES} + ${DRACO_LIBRARIES} ) + + if(Draco_FOUND) + message(STATUS "Draco found") + target_compile_definitions(pcd_benchmark PRIVATE DRACO_FOUND) + else() + message(STATUS "Draco not found, not using it in benchmarks") + endif() + else() message(STATUS "PCL not found, skipping pcd_benchmark") endif() diff --git a/cloudini_lib/benchmarks/pcd_benchmark.cpp b/cloudini_lib/benchmarks/pcd_benchmark.cpp index 2a690a5..1b0e62c 100644 --- a/cloudini_lib/benchmarks/pcd_benchmark.cpp +++ b/cloudini_lib/benchmarks/pcd_benchmark.cpp @@ -1,9 +1,15 @@ - #include #include #include #include +#ifdef DRACO_FOUND +#include +#include +#include +#include +#endif + #include "cloudini_lib/cloudini.hpp" #include "data_path.hpp" @@ -154,18 +160,64 @@ static void PCD_Decode_LZ4_only(benchmark::State& state) { PCD_Decode_Impl(state, cloud, info); } +//------------------------------------------------------------------------------------------ + +#ifdef DRACO_FOUND + +static void PCD_Encode_Draco(benchmark::State& state) { + const auto cloud = loadCloud(); + // Create Draco point cloud + draco::PointCloudBuilder builder; + builder.Start(cloud.size()); + + const int pos_att_id = builder.AddAttribute(draco::GeometryAttribute::POSITION, 3, draco::DT_FLOAT32); + const int intensity_att_id = builder.AddAttribute(draco::GeometryAttribute::GENERIC, 1, draco::DT_FLOAT32); + + // Add points to the point cloud + for (draco::PointIndex i(0); i < cloud.size(); ++i) { + const auto& point = cloud.points[i.value()]; + builder.SetAttributeValueForPoint(pos_att_id, i, &point.x); + builder.SetAttributeValueForPoint(intensity_att_id, i, &point.intensity); + } + + std::unique_ptr draco_pc = builder.Finalize(false); + if (!draco_pc) { + throw std::runtime_error("Failed to create Draco point cloud"); + } + + // Encode the point cloud + draco::ExpertEncoder encoder(*draco_pc); + encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 12); + encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, 8); + encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING); + + draco::EncoderBuffer buffer; + + for (auto _ : state) { + buffer.Clear(); + encoder.EncodeToBuffer(&buffer); + } + const auto percentage = + 100 * (static_cast(buffer.size()) / static_cast(cloud.size() * sizeof(pcl::PointXYZI))); + std::cout << "Encoded size: " << buffer.size() << " percentage: " << percentage << "%" << std::endl; +} + +#endif + +//------------------------------------------------------------------------------------------ + BENCHMARK(PCD_Encode_Lossy_ZST); -BENCHMARK(PCD_Encode_Lossles_ZST); BENCHMARK(PCD_Encode_ZSTD_only); BENCHMARK(PCD_Encode_Lossy_LZ4); -BENCHMARK(PCD_Encode_Lossles_LZ4); BENCHMARK(PCD_Encode_LZ4_only); +#ifdef DRACO_FOUND +BENCHMARK(PCD_Encode_Draco); +#endif + BENCHMARK(PCD_Decode_Lossy_ZST); BENCHMARK(PCD_Decode_Lossy_LZ4); - BENCHMARK(PCD_Decode_ZSTD_only); BENCHMARK(PCD_Decode_LZ4_only); -//------------------------------------------------------------------------------------------ BENCHMARK_MAIN(); diff --git a/cloudini_lib/tools/CMakeLists.txt b/cloudini_lib/tools/CMakeLists.txt index 1d9407e..2f05cf3 100644 --- a/cloudini_lib/tools/CMakeLists.txt +++ b/cloudini_lib/tools/CMakeLists.txt @@ -4,7 +4,7 @@ if(NOT TARGET fastcdr) NAME fastcdr_imported GITHUB_REPOSITORY eProsima/Fast-CDR GIT_TAG v2.2.6 - OPTIONS "BUILD_SHARED_LIBS OFF" + OPTIONS "BUILD_SHARED_LIBS OFF;BUILD_TESTING OFF" ) endif()