diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..578911e --- /dev/null +++ b/.clang-format @@ -0,0 +1,19 @@ +--- +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +AccessModifierOffset: -4 +AllowShortFunctionsOnASingleLine: Inline +BreakBeforeBraces: Attach +IndentCaseLabels: true +NamespaceIndentation: None +PointerAlignment: Left +ReferenceAlignment: Left +SortIncludes: Never +SpaceAfterCStyleCast: false +SpacesInParentheses: false +Standard: c++11 +--- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5c078f8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,66 @@ +# +# Copyright (c) 2026 Junhang Lai (赖俊杭) +# +# SPDX-License-Identifier: Apache-2.0 +# + +name: CI + +on: + push: + branches: [master, feature/*] + pull_request: + branches: [master] + +jobs: + build: + name: Build / ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Configure + run: cmake -B build -DBUILD_TESTING=ON -DBUILD_DOCUMENTATION=OFF + + - name: Build + run: cmake --build build --config Release -j 4 + + - name: Test + run: ctest --test-dir build --output-on-failure -C Release + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Doxygen + run: sudo apt-get update && sudo apt-get install -y doxygen graphviz + + - name: Configure + run: cmake -B build -DBUILD_TESTING=OFF -DBUILD_DOCUMENTATION=ON + + - name: Build docs + run: cmake --build build --target heuclid-doc + + - name: Check docs generated + run: | + if [ -d "build/doc/doxygen-html" ]; then + echo "✅ Doxygen HTML docs generated" + ls build/doc/doxygen-html/ | head -10 + else + echo "❌ No HTML output found" + find build/doc -type f 2>/dev/null | head -10 + exit 1 + fi diff --git a/.gitignore b/.gitignore index b757ae1..3fc85d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,28 @@ -# Prerequisites -*.d +# Build directories +build/ +_build/ +cmake-build-*/ -# Compiled Object files -*.slo -*.lo -*.o -*.obj +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ -# Precompiled Headers -*.gch -*.pch +# OS +.DS_Store +Thumbs.db -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod +# Doxygen output +doc/html/ +doc/latex/ -# Compiled Static libraries -*.lai -*.la -*.a +# Compiled +*.o +*.obj *.lib - -# Executables -*.exe -*.out -*.app - -# Cmake Build Folders -build/ -src/Test/build/ +*.a +*.so +*.dll +*.dylib diff --git a/CMakeLists.txt b/CMakeLists.txt index ad66368..fbfdec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,67 +1,179 @@ -cmake_minimum_required(VERSION 3.0) -set(PROJECT_NAME Heuclid) -project(${PROJECT_NAME} VERSION 0.1) - -find_package(Eigen3 REQUIRED) -include_directories(${EIGEN3_INCLUDE_DIR}) -message(STATUS "Eigen3 is in ${EIGEN3_INCLUDE_DIR}") - -message("Build type is ${CMAKE_BUILD_TYPE}") - -add_compile_options(-std=c++14) -add_compile_options(/MT) - -set(ROOT_PATH ..) - -include(./cmake/HeuclidConfig.cmake) - -include_directories(./include) -include_directories(./include/Heuclid) -include_directories(./include/Heuclid/euclid) -include_directories(./include/Heuclid/geometry) -include_directories(./include/Heuclid/title) - -aux_source_directory(./src/Heuclid/euclid SRC_FILES) -aux_source_directory(./src/Heuclid/euclid/orientation SRC_FILES) -aux_source_directory(./src/Heuclid/euclid/tools SRC_FILES) -aux_source_directory(./src/Heuclid/euclid/tuple2D SRC_FILES) -aux_source_directory(./src/Heuclid/euclid/tuple3D SRC_FILES) -aux_source_directory(./src/Heuclid/euclid/tuple4D SRC_FILES) -aux_source_directory(./src/Heuclid/geometry/tools SRC_FILES) -aux_source_directory(./src/Heuclid/geometry SRC_FILES) - -set(BUILD_TEST 0) -set(NEED_PLOT 1) -if(BUILD_TEST) - set(CMAKE_BUILD_TYPE Debug) - - - add_executable(test src/Test/test.cpp ${SRC_FILES}) - if(NEED_PLOT) - find_package(matplotlib_cpp REQUIRED) - target_link_libraries(test ${matplotlib_LIBS}) - endif() +# +# Copyright (c) 2026 Junhang Lai (赖俊杭) +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.22) + +# Project setup +set(PROJECT_NAME heuclid) +set(PROJECT_DESCRIPTION + "A C++ library for Euclidean geometry, convex hull, and geometric computation" +) +set(PROJECT_URL "https://github.com/Mr-tooth/Heuclid") +set(PROJECT_CUSTOM_HEADER_EXTENSION "h") +set(PROJECT_USE_CMAKE_EXPORT TRUE) +set(PROJECT_USE_KEYWORD_LINK_LIBRARIES TRUE) +set(PROJECT_COMPATIBILITY_VERSION AnyNewerVersion) +set(PROJECT_AUTO_RUN_FINALIZE FALSE) + +# --------------------------------------------------------------------------- +# --- jrl-cmakemodules: three-tier lookup ------------------------------- +# 1) Git submodule under cmake/jrl-cmakemodules/ +# 2) System-installed (find_package) +# 3) FetchContent (auto-download) +# --------------------------------------------------------------------------- +set(JRL_CMAKE_MODULES "${CMAKE_CURRENT_LIST_DIR}/cmake/jrl-cmakemodules") +if(EXISTS "${JRL_CMAKE_MODULES}/base.cmake") + message(STATUS "JRL cmakemodules found in 'cmake/jrl-cmakemodules/' (submodule)") +else() + find_package(jrl-cmakemodules QUIET CONFIG) + if(jrl-cmakemodules_FOUND) + get_property( + JRL_CMAKE_MODULES + TARGET jrl-cmakemodules::jrl-cmakemodules + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ) + message(STATUS "JRL cmakemodules found on system at ${JRL_CMAKE_MODULES}") + else() + message(STATUS "JRL cmakemodules not found. Fetching from GitHub...") + include(FetchContent) + FetchContent_Declare( + "jrl-cmakemodules" + GIT_REPOSITORY "https://github.com/jrl-umi3218/jrl-cmakemodules.git" + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable("jrl-cmakemodules") + FetchContent_GetProperties("jrl-cmakemodules" SOURCE_DIR JRL_CMAKE_MODULES) + message(STATUS "JRL cmakemodules fetched to ${JRL_CMAKE_MODULES}") + endif() +endif() + +# Doxygen settings (must be before base.cmake) +set(DOXYGEN_USE_MATHJAX YES) +set(DOXYGEN_FILE_PATTERNS "*.h") +set(DOXYGEN_HTML_OUTPUT "doxygen-html") +option(BUILD_DOCUMENTATION "Build Doxygen documentation" ON) +option(INSTALL_DOCUMENTATION "Install Doxygen documentation" OFF) + +# --------------------------------------------------------------------------- +# --- Project declaration --------------------------------------------------- +# --------------------------------------------------------------------------- +include("${JRL_CMAKE_MODULES}/base.cmake") +compute_project_args(PROJECT_ARGS LANGUAGES CXX) +project(${PROJECT_NAME} ${PROJECT_ARGS}) + +include("${JRL_CMAKE_MODULES}/ide.cmake") +include("${JRL_CMAKE_MODULES}/apple.cmake") +# NOTE: Doxygen is handled automatically by base.cmake when BUILD_DOCUMENTATION=ON + +apply_default_apple_configuration() + +# C++ standard: minimum C++11 +check_minimal_cxx_standard(11 ENFORCE) + +# --------------------------------------------------------------------------- +# --- Dependencies ---------------------------------------------------------- +# --------------------------------------------------------------------------- +# Eigen3: header-only, INTERFACE target. Use FetchContent with version lock. +find_package(Eigen3 3.3 QUIET CONFIG) +if(NOT TARGET Eigen3::Eigen) + message(STATUS "Eigen3 not found - fetching 3.4.0 via FetchContent") + include(FetchContent) + FetchContent_Declare( + Eigen3 + GIT_REPOSITORY "https://gitlab.com/libeigen/eigen.git" + GIT_TAG "3.4.0" + GIT_SHALLOW TRUE + ) + # Eigen3 is header-only — just populate, no add_subdirectory. + # This avoids target name conflicts (e.g. 'uninstall') with jrl-cmakemodules. + FetchContent_GetProperties(Eigen3) + if(NOT eigen3_POPULATED) + FetchContent_Populate(Eigen3) + endif() + # IMPORTED: CMake won't try to export this target + add_library(Eigen3::Eigen INTERFACE IMPORTED) + set_target_properties(Eigen3::Eigen PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${eigen3_SOURCE_DIR}" + ) + set(Eigen3_FOUND TRUE) + set(Eigen3_VERSION "3.4.0") + set(_HEUCLID_EIGEN_FETCHED TRUE) + message(STATUS "Eigen3 fetched: ${eigen3_SOURCE_DIR}") else() - set(CMAKE_BUILD_TYPE Release) - add_compile_options(/O2) -# Build Heuclid static library -add_library(${LIB_NAME} STATIC ${SRC_FILES}) + message(STATUS "Eigen3 found: ${Eigen3_VERSION}") +endif() + +# Register Eigen3 as a dependency for the generated Config.cmake +# Skip when Eigen3 was fetched (not found via find_package) to avoid +# add_project_dependency calling find_package again and failing. +if(Eigen3_VERSION AND NOT _HEUCLID_EIGEN_FETCHED) + add_project_dependency(Eigen3 REQUIRED) endif() -# Set instal configuration -message("Install path is ${CMAKE_INSTALL_PREFIX}") +# --------------------------------------------------------------------------- +# --- Options --------------------------------------------------------------- +# --------------------------------------------------------------------------- +option(BUILD_TESTING "Build unit tests" ON) +# BUILD_DOCUMENTATION is set before base.cmake include above + +# --------------------------------------------------------------------------- +# --- Heuclid library (header-only INTERFACE) ------------------------------- +# --------------------------------------------------------------------------- +add_library(${PROJECT_NAME} INTERFACE) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +target_include_directories( + ${PROJECT_NAME} + INTERFACE $ + $ +) + +target_link_libraries(${PROJECT_NAME} INTERFACE Eigen3::Eigen) + +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_11) + +# --------------------------------------------------------------------------- +# --- Doxygen documentation ------------------------------------------------- +# --------------------------------------------------------------------------- +# jrl-cmakemodules (base.cmake) automatically creates {PROJECT_NAME}-doc target +# when BUILD_DOCUMENTATION=ON and Doxygen is found. +# Customize Doxygen output via DOXYGEN_* variables (set before base.cmake include). +# To build: cmake --build build --target heuclid-doc + +# --------------------------------------------------------------------------- +# --- Testing --------------------------------------------------------------- +# --------------------------------------------------------------------------- +if(BUILD_TESTING) + enable_testing() + add_subdirectory(src/Test) +endif() -set(Heuclid_include_dirs ${CMAKE_INSTALL_PREFIX}/include) -set(Heuclid_link_dirs ${CMAKE_INSTALL_PREFIX}/lib) -# set(Heuclid_src) +# --------------------------------------------------------------------------- +# --- Install --------------------------------------------------------------- +# --------------------------------------------------------------------------- +include(GNUInstallDirs) -configure_file(Heuclid.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/HeuclidConfig.cmake @ONLY) - -install(FILES ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/HeuclidConfig.cmake DESTINATION share/Heuclid/cmake) -install(FILES ${PROJECT_BINARY_DIR}/Release/Heuclid.lib DESTINATION lib) -install(DIRECTORY include/Heuclid DESTINATION include) +# Install headers +install( + DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.h" +) +# Install CMake package configuration +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets +) -# add test -add_subdirectory(src/Test) +# NOTE: Config.cmake, ConfigVersion.cmake, and export install are handled +# by setup_project_finalize() via jrl-cmakemodules (package-config.cmake). +# --------------------------------------------------------------------------- +# --- Finalize (generates Doxyfile, pkg-config, coverage, etc.) ------------- +# --------------------------------------------------------------------------- +setup_project_finalize() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..18d7f2a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,43 @@ +# Contributing to Heuclid + +Thank you for your interest in contributing to Heuclid! + +## Development Setup + +```bash +git clone --recursive https://github.com/Mr-tooth/Heuclid.git +cd Heuclid +cmake -B build -DBUILD_TESTING=ON +cmake --build build +ctest --test-dir build +``` + +## Code Style + +- C++11 standard +- Google-style formatting (see `.clang-format`) +- All public APIs must have Doxygen documentation +- Run `clang-format` before committing + +## Pull Request Process + +1. Fork and create a feature branch from `master` +2. Ensure all tests pass: `ctest --test-dir build` +3. Add tests for new functionality +4. Update documentation (Doxygen comments) +5. Submit PR with clear description + +## Commit Messages + +Follow [Conventional Commits](https://www.conventionalcommits.org/): + +- `feat:` new feature +- `fix:` bug fix +- `docs:` documentation only +- `build:` build system changes +- `test:` test additions/changes +- `refactor:` code restructuring + +## License + +By contributing, you agree that your contributions will be licensed under the Apache License 2.0. diff --git a/Heuclid.cmake.in b/Heuclid.cmake.in deleted file mode 100644 index 514a980..0000000 --- a/Heuclid.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -# - Config file for the Heuclid package -# It defines the following variables -# HEUCLID_INCLUDE_DIRS - include directory -# HEUCLID_LINK_DIRS - link library - -# compute paths -set(HEUCLID_INCLUDE_DIRS "@Heuclid_include_dirs@") -set(HEUCLID_LINK_DIRS "@Heuclid_link_dirs@" ) - -# include paths -include_directories(${HEUCLID_INCLUDE_DIRS}) -link_directories(${HEUCLID_LINK_DIRS}) -message("--[Heuclid]: Package found! Include ${HEUCLID_INCLUDE_DIRS} and ${HEUCLID_LINK_DIRS}") \ No newline at end of file diff --git a/README.md b/README.md index fb1ed41..dd2381b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,111 @@ -# Heuclid - Heuclid is a general library addressing vector math and geometry problems in C++. +
+ +# 🔷 Heuclid + +**A C++ library for Euclidean geometry, convex hull, and geometric computation** + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) +[![C++](https://img.shields.io/badge/C%2B%2B-11%2B-blue.svg)](https://en.cppreference.com/w/cpp/11) +[![Build](https://img.shields.io/badge/CMake-3.22%2B-blue.svg)](https://cmake.org/) +[![Eigen](https://img.shields.io/badge/Eigen-3.x-blue.svg)](https://eigen.tuxfamily.org/) + +[English](#english) | [中文](README_zh.md) + +
+ +--- + +## English + +### Overview + +**Heuclid** is a lightweight, header-only C++ library providing fundamental Euclidean geometry primitives and algorithms. Built on [Eigen](https://eigen.tuxfamily.org/), it is designed for robotics simulation, motion planning, and computational geometry applications. + +### Features + +- **2D/3D Primitives** — Points, vectors, unit vectors, quaternions, poses +- **Convex Hull** — Graham scan and Gift wrapping algorithms with half-space representation (A*x ≤ b) +- **Bézier Curves** — N-th order Bézier with analytical derivatives +- **Eigen Interoperability** — Seamless conversion between Heuclid types and Eigen matrices +- **Header-Only** — No linking required, just include and use +- **C++11 Compatible** — Works with any C++11-compliant compiler + +### Quick Start + +```bash +# Clone with submodules +git clone --recursive https://github.com/Mr-tooth/Heuclid.git +cd Heuclid + +# Build (fetches jrl-cmakemodules and GoogleTest automatically) +cmake -B build -DBUILD_TESTING=ON +cmake --build build + +# Run tests +ctest --test-dir build +``` + +### Using in Your Project + +```cmake +# CMakeLists.txt +add_subdirectory(path/to/Heuclid) +target_link_libraries(your_target PRIVATE heuclid) +``` + +```cpp +#include +#include + +using ljh::heuclid::Point2D; +using ljh::heuclid::Pose3D; + +Point2D p1(1.0, 2.0); +Point2D p2(3.0, 4.0); +double dist = p1.distance(p2); + +Pose3D pose(0, 0, 0, 0, 0, 0); +``` + +### Dependencies + +| Dependency | Version | Required | +|------------|---------|----------| +| [Eigen](https://eigen.tuxfamily.org/) | 3.x | ✅ Yes | +| [jrl-cmakemodules](https://github.com/jrl-umi3218/jrl-cmakemodules) | - | Auto-fetched | +| [GoogleTest](https://github.com/google/googletest) | 1.14+ | Testing only | + +### Project Structure + +``` +Heuclid/ +├── include/Heuclid/ +│ ├── euclid/ # Core Euclidean primitives +│ │ ├── tuple2D/ # Point2D, Vector2D, UnitVector2D +│ │ ├── tuple3D/ # Point3D, Vector3D, UnitVector3D +│ │ ├── tuple4D/ # Quaternion +│ │ ├── orientation/ # Orientation2D +│ │ ├── tools/ # CoreTool, QuaternionTool +│ │ └── interfaces/ # ZeroTestEpsilon +│ ├── geometry/ # Geometric algorithms +│ │ ├── ConvexHull2D.h # Convex hull (Graham scan, Gift wrapping) +│ │ ├── ConvexPolygon2D.h +│ │ ├── Line2D.h +│ │ ├── Pose2D.h / Pose3D.h +│ │ ├── curves/ # Bézier curves (Func.h) +│ │ └── tools/ # Geometry/Polygon utilities +│ └── title/ # Namespace macros +└── src/Test/ # GoogleTest unit tests +``` + +### License + +Licensed under the [Apache License 2.0](LICENSE). + +### Author + +**Junhang Lai (赖俊杭)** + +--- + +_This library is a dependency of [AStarFootstepPlanner](https://github.com/Mr-tooth/AStarFootstepPlanner) and other robotics projects._ diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..8b76af8 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,105 @@ +
+ +# 🔷 Heuclid + +**C++ 欧几里得几何与凸包计算库** + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) +[![C++](https://img.shields.io/badge/C%2B%2B-11%2B-blue.svg)](https://en.cppreference.com/w/cpp/11) +[![CMake](https://img.shields.io/badge/CMake-3.22%2B-blue.svg)](https://cmake.org/) +[![Eigen](https://img.shields.io/badge/Eigen-3.x-blue.svg)](https://eigen.tuxfamily.org/) + +[English](README.md) | [中文](#中文) + +
+ +--- + +## 中文 + +### 概述 + +**Heuclid** 是一个轻量级的 header-only C++ 库,提供基础欧几里得几何原语和算法。基于 [Eigen](https://eigen.tuxfamily.org/) 构建,适用于机器人仿真、运动规划和计算几何应用。 + +### 特性 + +- **2D/3D 基础类型** — 点、向量、单位向量、四元数、位姿 +- **凸包计算** — Graham 扫描和 Gift wrapping 算法,支持半空间表达 (A*x ≤ b) +- **贝塞尔曲线** — N 阶贝塞尔曲线及其解析导数 +- **Eigen 互操作** — Heuclid 类型与 Eigen 矩阵无缝转换 +- **Header-Only** — 无需链接,include 即用 +- **C++11 兼容** — 支持所有 C++11 标准编译器 + +### 快速开始 + +```bash +# 克隆(含子模块) +git clone --recursive https://github.com/Mr-tooth/Heuclid.git +cd Heuclid + +# 构建(自动获取 jrl-cmakemodules 和 GoogleTest) +cmake -B build -DBUILD_TESTING=ON +cmake --build build + +# 运行测试 +ctest --test-dir build +``` + +### 在项目中使用 + +```cmake +# CMakeLists.txt +add_subdirectory(path/to/Heuclid) +target_link_libraries(your_target PRIVATE heuclid) +``` + +```cpp +#include +#include + +using ljh::heuclid::Point2D; +using ljh::heuclid::Pose3D; + +Point2D p1(1.0, 2.0); +Point2D p2(3.0, 4.0); +double dist = p1.distance(p2); +``` + +### 依赖 + +| 依赖 | 版本 | 必需 | +|------|------|------| +| [Eigen](https://eigen.tuxfamily.org/) | 3.x | ✅ | +| [jrl-cmakemodules](https://github.com/jrl-umi3218/jrl-cmakemodules) | - | 自动获取 | +| [GoogleTest](https://github.com/google/googletest) | 1.14+ | 仅测试 | + +### 项目结构 + +``` +Heuclid/ +├── include/Heuclid/ +│ ├── euclid/ # 欧几里得基础类型 +│ │ ├── tuple2D/ # Point2D, Vector2D, UnitVector2D +│ │ ├── tuple3D/ # Point3D, Vector3D, UnitVector3D +│ │ ├── tuple4D/ # Quaternion +│ │ ├── orientation/ # Orientation2D +│ │ └── tools/ # CoreTool, QuaternionTool +│ ├── geometry/ # 几何算法 +│ │ ├── ConvexHull2D.h # 凸包(Graham scan, Gift wrapping) +│ │ ├── Line2D.h / Pose2D.h / Pose3D.h +│ │ └── curves/ # 贝塞尔曲线 +│ └── title/ # 命名空间宏 +└── src/Test/ # GoogleTest 单元测试 +``` + +### 许可证 + +[Apache License 2.0](LICENSE) + +### 作者 + +**赖俊航 (Junhang Lai)** + +--- + +_本库是 [AStarFootstepPlanner](https://github.com/Mr-tooth/AStarFootstepPlanner) 等机器人项目的依赖库。_ diff --git a/cmake/HeuclidConfig.cmake b/cmake/HeuclidConfig.cmake deleted file mode 100644 index d07c343..0000000 --- a/cmake/HeuclidConfig.cmake +++ /dev/null @@ -1,15 +0,0 @@ -set(LIB_NAME Heuclid) -set(PATH_NAME Heuclid) -set(${LIB_NAME}_DIR ${ROOT_PATH}/${PATH_NAME}) - -message("--[${LIB_NAME}]:Hello! I'm in ${${LIB_NAME}_DIR}") - -include_directories(${${LIB_NAME}_DIR}/include) -include_directories(${${LIB_NAME}_DIR}/include/Heuclid) -include_directories(${${LIB_NAME}_DIR}/include/Heuclid/euclid) -include_directories(${${LIB_NAME}_DIR}/include/Heuclid/geometry) -include_directories(${${LIB_NAME}_DIR}/include/Heuclid/title) - - -aux_source_directory(${${LIB_NAME}_DIR}/src/Heuclid/euclid/orientation ALL_SRC_FILES) -aux_source_directory(${${LIB_NAME}_DIR}/src/Heuclid/euclid/tools ALL_SRC_FILES) \ No newline at end of file diff --git a/doc/Doxyfile.extra.in b/doc/Doxyfile.extra.in new file mode 100644 index 0000000..73a3b67 --- /dev/null +++ b/doc/Doxyfile.extra.in @@ -0,0 +1,10 @@ +# Doxyfile.extra.in for Heuclid +# Appended to jrl-cmakemodules generated Doxyfile +# Uses Doxygen key = value syntax (not @VAR@ substitution) + +EXCLUDE_PATTERNS = */title/* + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +PREDEFINED = _LJH_EUCLID_LIB_BEGIN= _LJH_EUCLID_LIB_END= diff --git a/include/Heuclid/euclid/interfaces/ZeroTestEpsilon.h b/include/Heuclid/euclid/interfaces/ZeroTestEpsilon.h index 2252fca..4adf4ec 100644 --- a/include/Heuclid/euclid/interfaces/ZeroTestEpsilon.h +++ b/include/Heuclid/euclid/interfaces/ZeroTestEpsilon.h @@ -1,5 +1,11 @@ #pragma once +/** + * @file ZeroTestEpsilon.h + * @brief Epsilon-based floating point zero test interface. + * @author Junhang Lai (赖俊杭) + */ #ifndef ZERO_TEST_EPSILON +/** @brief Default epsilon for floating point zero comparison. */ #define ZERO_TEST_EPSILON 1e-6 #endif \ No newline at end of file diff --git a/include/Heuclid/euclid/orientation/Orientation2D.h b/include/Heuclid/euclid/orientation/Orientation2D.h index 7d5b93d..eb13368 100644 --- a/include/Heuclid/euclid/orientation/Orientation2D.h +++ b/include/Heuclid/euclid/orientation/Orientation2D.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file Orientation2D.h + * @brief 2D orientation representation (yaw angle). + * @author Junhang Lai (赖俊杭) + */ #ifndef __Orientation__2D__ #define __Orientation__2D__ @@ -8,6 +13,7 @@ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN +/** @brief 2D orientation represented as a yaw angle with trigonometric caching. */ class Orientation2D { public: diff --git a/include/Heuclid/euclid/tools/HeuclidCoreTool.h b/include/Heuclid/euclid/tools/HeuclidCoreTool.h index 8f8f355..e9c6ead 100644 --- a/include/Heuclid/euclid/tools/HeuclidCoreTool.h +++ b/include/Heuclid/euclid/tools/HeuclidCoreTool.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file HeuclidCoreTool.h + * @brief Core utility functions for geometric computation. + * @author Junhang Lai (赖俊杭) + */ #include #include diff --git a/include/Heuclid/euclid/tools/QuaternionTool.h b/include/Heuclid/euclid/tools/QuaternionTool.h index 1c646a4..a96829c 100644 --- a/include/Heuclid/euclid/tools/QuaternionTool.h +++ b/include/Heuclid/euclid/tools/QuaternionTool.h @@ -1,39 +1,56 @@ +/** + * @file QuaternionTool.h + * @brief Quaternion utility functions (Euler conversion, etc.). + * @author Junhang Lai (赖俊杭) + */ #pragma once #include #include _LJH_EUCLID_LIB_BEGIN - +/** + * @name Quaternion multiplication functions + * @brief Quaternion multiplication with optional conjugation. + * + * @tparam dataType The scalar type. + * @param q1 First quaternion. + * @param q2 Second quaternion. + * @param store Output quaternion (q1 * q2 or conjugated variants). + */ +///@{ + +/** @brief Standard quaternion multiplication: store = q1 * q2. */ template void multiply(const Quaternion& q1, const Quaternion& q2, Quaternion& store) { multiplyImpl(q1,false,q2,false,store); } +/** @brief Multiply with conjugated left: store = q1* * q2. */ template void multiplyConjugateLeft(const Quaternion& q1, const Quaternion& q2, Quaternion& store) { multiplyImpl(q1,true,q2,false,store); } +/** @brief Multiply with conjugated right: store = q1 * q2*. */ template void multiplyConjugateRight(const Quaternion& q1, const Quaternion& q2, Quaternion& store) { multiplyImpl(q1,false,q2,true,store); } +/** @brief Multiply with both conjugated: store = q1* * q2*. */ template void multiplyConjugateBoth(const Quaternion& q1, const Quaternion& q2, Quaternion& store) { multiplyImpl(q1,true,q2,true,store); } +///@} - - - - +/** @brief Internal implementation of quaternion multiplication with conjugation flags. */ template void multiplyImpl(const Quaternion& q1,bool conjugateQ1, const Quaternion& q2, bool conjugateQ2, Quaternion& store) { diff --git a/include/Heuclid/euclid/tuple2D/Point2D.h b/include/Heuclid/euclid/tuple2D/Point2D.h index e047196..c8bd40a 100644 --- a/include/Heuclid/euclid/tuple2D/Point2D.h +++ b/include/Heuclid/euclid/tuple2D/Point2D.h @@ -1,62 +1,84 @@ +/** + * @file Point2D.h + * @brief 2D point representation with arithmetic operations and Eigen interop. + * @author Junhang Lai (赖俊杭) + */ + #pragma once #ifndef __Point__2D__ #define __Point__2D__ #include #include + #define _LJH_EUCLID_LIB_BEGIN namespace ljh{namespace heuclid{ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN -/* -* A 2D point represents the 2D coordinates of a location on the XY-plane. -* */ + +/** + * @brief A 2D point representing coordinates on the XY-plane. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Provides basic 2D point operations including arithmetic (+, -, *, /), + * distance computation, norm, and full Eigen::Matrix interoperability. + * + * @code + * Point2D p1(1.0, 2.0); + * Point2D p2(3.0, 4.0); + * double dist = p1.distance(p2); + * Eigen::Vector2d ev = Eigen::Vector2d(5.0, 6.0); + * Point2D p3 = p1 + ev; // Eigen interop + * @endcode + */ template class Point2D { public: + /** @brief Default constructor. Initializes to origin (0, 0). */ Point2D():x(dataType(0)),y(dataType(0)){}; + + /** @brief Construct from x and y coordinates. */ Point2D(dataType _x,dataType _y):x(_x),y(_y){}; + + /** @brief Copy constructor. */ Point2D(const Point2D& other):x(other.x),y(other.y){}; + + /** @brief Construct from an Eigen 2D vector. */ Point2D(const Eigen::Matrix& other):x(other(0)),y(other(1)){}; + /** @name Getters */ + ///@{ inline dataType getX() const {return this->x;}; inline dataType getY() const {return this->y;}; + ///@} + + /** @name Setters */ + ///@{ inline void setX(const dataType& _x) {this->x = _x;}; inline void setY(const dataType& _y) {this->y = _y;}; inline void setPoint2D(const dataType& _x,const dataType& _y) {this->x = _x;this->y = _y;}; inline void setPoint2D(const Point2D& other) {this->x =other.x;this->y = other.y;}; inline void setPoint2D(const Eigen::Matrix& other) {this->x =other(0);this->y = other(1);}; + ///@} - //inline bool operator==(dataType _null) {return (this->x==_null&&this->y==_null);}; - + /** @name Comparison operators */ + ///@{ inline bool operator==(const Point2D& other) const { return (this->x == other.x && this->y == other.y); }; - - // 兼容Eigen库 + /** @brief Eigen interoperability comparison. */ inline bool operator==(const Eigen::Matrix& other) const { return (this->x == other(0) && this->y == other(1)); }; + ///@} - // {return (this->getX()==other.getX()&& - // this->getY()==other.getY());}; - - // inline Point2D operator=(const Point2D & other) - // { - // Point2D point; - // point.setX(other.getX() ); - // point.setY(other.getY() ); - // return point; - // } - - // 重载运算符 + - * / - - - + /** @name Arithmetic operators */ + ///@{ inline Point2D operator+(const Point2D & other) const { Point2D point; @@ -65,7 +87,7 @@ class Point2D return point; } - // 兼容Eigen库 + /** @brief Eigen interoperability addition. */ inline Point2D operator+(const Eigen::Matrix& other) const { Point2D point; @@ -82,7 +104,7 @@ class Point2D return point; } - // 兼容Eigen库 + /** @brief Element-wise multiplication with Eigen vector. */ inline Point2D operator*(const Eigen::Matrix& scale) const { Point2D point; @@ -99,7 +121,7 @@ class Point2D return point; } - // 兼容Eigen库 + /** @brief Eigen interoperability subtraction. */ inline Point2D operator-(const Eigen::Matrix& other) const { Point2D point; @@ -116,7 +138,7 @@ class Point2D return point; } - // 兼容Eigen库 + /** @brief Element-wise division with Eigen vector. */ inline Point2D operator/(const Eigen::Matrix& scale) const { Point2D point; @@ -131,7 +153,6 @@ class Point2D return *this; } - // 兼容Eigen库 inline Point2D operator+=(const Eigen::Matrix& other) { this->setPoint2D(this->getX() + other(0), this->getY() + other(1)); @@ -144,7 +165,6 @@ class Point2D return *this; } - // 兼容Eigen库 inline Point2D operator-=(const Eigen::Matrix& other) { this->setPoint2D(this->getX() - other(0), this->getY() - other(1)); @@ -157,7 +177,6 @@ class Point2D return *this; } - // 兼容Eigen库 inline Point2D operator*=(const Eigen::Matrix& scale) { this->setPoint2D(this->getX() * scale(0), this->getY() * scale(1)); @@ -170,7 +189,6 @@ class Point2D return *this; } - // 兼容Eigen库 inline Point2D operator/=(const Eigen::Matrix& scale) { this->setPoint2D(this->getX() / scale(0), this->getY() / scale(1)); @@ -199,14 +217,18 @@ class Point2D return *this; } - // 兼容Eigen库 inline Point2D operator=(const Eigen::Matrix& other) { this->setPoint2D(other(0), other(1)); return *this; } + ///@} - // get the distance between two points, return the data type of the point + /** + * @brief Compute Euclidean distance to another point. + * @param other The target point. + * @return The distance as dataType. + */ dataType distance(const Point2D& other) const { double dx = this->getX()-other.getX(); @@ -214,31 +236,48 @@ class Point2D return ::std::sqrt(dx*dx+dy*dy); } - // get the norm of the point, return the data type of the point + /** + * @brief Compute the Euclidean norm (distance to origin). + * @return The norm as dataType. + */ dataType norm() const { return ::std::sqrt(this->getX()*this->getX()+this->getY()*this->getY()); } - // reload the << operator for cout + /** @brief Stream output operator. */ friend std::ostream& operator<<(std::ostream& os, const Point2D& point) { os << "(" << point.getX() << "," << point.getY() << ")"; return os; } - + /** + * @brief Check if two points are equal within an epsilon tolerance. + * @param other The point to compare. + * @param epsilon The tolerance threshold. + * @return True if |dx| <= epsilon and |dy| <= epsilon. + */ bool epsilonEquals(const Point2D& other, const double& epsilon) const; + + /** + * @brief Check if two points are geometrically equal (Euclidean distance). + * @param other The point to compare. + * @param epsilon The distance threshold. + * @return True if distance <= epsilon. + */ bool geometricallyEquals(const Point2D& other, const double& epsilon) const; - bool epsilonZero(const double& epsilon); - // inline void operator= (const Point2D& other) {this->x =other.x;this->y = other.y;}; - // inline void operator= (const Eigen::Matrix& other) {this->x =other(0);this->y = other(1);}; - //inline void operator==(const Point2D& other) {return (this->x==other.x&&this->y==other.y);}; + /** + * @brief Check if point is at origin within epsilon. + * @param epsilon The tolerance threshold. + * @return True if both coordinates are within epsilon of zero. + */ + bool epsilonZero(const double& epsilon); private: - dataType x; - dataType y; + dataType x; ///< X coordinate + dataType y; ///< Y coordinate }; template @@ -262,11 +301,6 @@ bool Point2D::epsilonZero(const double& epsilon) return (std::abs(this->getX())<=epsilon && std::abs(this->getY())<=epsilon); } - - - - - _LJH_EUCLID_LIB_END -#endif \ No newline at end of file +#endif diff --git a/include/Heuclid/euclid/tuple2D/UnitVector2D.h b/include/Heuclid/euclid/tuple2D/UnitVector2D.h index 11ca6a9..015f74a 100644 --- a/include/Heuclid/euclid/tuple2D/UnitVector2D.h +++ b/include/Heuclid/euclid/tuple2D/UnitVector2D.h @@ -1,59 +1,92 @@ +/** + * @file UnitVector2D.h + * @brief 2D unit vector with automatic normalization. + * @author Junhang Lai (赖俊杭) + */ + #pragma once #ifndef __UNIT__VECTOR__2D__ #define __UNIT__VECTOR__2D__ #include #include + #define _LJH_EUCLID_LIB_BEGIN namespace ljh{namespace heuclid{ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN + /** - * Implementation for a 2 dimensional unit-length vector. - *

- * This unit vector shares the same API as a regular vector 2D while ensuring it is normalized when - * accessing directly or indirectly its individual components, i.e. when invoking either - * {@link #getX()} or {@link #getY()}. + * @brief A 2D unit-length vector with lazy normalization. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Shares the same API as Vector2D while ensuring unit length. + * Uses a dirty flag for lazy normalization — the vector is only + * normalized when components are accessed (getX/getY). * - * When the values of this vector are set to zero, the next time it is normalized it will be reset - * to (1.0, 0.0). - * */ + * When set to zero, the next normalization resets to (1, 0). + */ template class UnitVector2D { public: - // SetZero means set the vector refer to X(1,0) axis + /** @brief Default constructor. Initializes to (1, 0) — the X-axis unit vector. */ UnitVector2D():x(dataType(1)),y(dataType(0)),dirty(true){}; + + /** @brief Construct from components. Will be normalized on first access. */ UnitVector2D(dataType _x, dataType _y):x(_x),y(_y),dirty(true){}; + + /** @brief Copy constructor. */ UnitVector2D(const UnitVector2D& other); + /** @brief Set all components to absolute values. */ inline void absolute(){this->x = std::abs(this->x);this->y = std::abs(this->y);}; + + /** @brief Negate the vector direction. */ inline void negate(){this->x = - this->x;this->y = - this->y;}; + + /** @brief Force normalization. Resets to (1,0) if currently zero. */ void normalize(); - //bool operator==(const dataType& epsl) const {return (this->x == epsl && this->y == epsl);}; - + + /** @brief Equality comparison. */ bool operator==(const UnitVector2D& other) const {return (this->x==other.x&&this->y=other.y);}; + /** @brief Check if components are within epsilon of zero. */ bool equals(const dataType& epsl) const {return (std::abs(this->x) <= epsl && std::abs(this->y) <= epsl);}; + /** @brief Mark vector as needing re-normalization. */ inline void markAsDirty() {this->dirty = true;}; + + /** @brief Check if vector needs re-normalization. */ inline bool isDirty() const {return this->dirty;}; + /** @brief Set X component (marks dirty). */ void setX(dataType _x); + + /** @brief Set Y component (marks dirty). */ void setY(dataType _y); + + /** @brief Get raw X component without normalization. */ dataType getRawX() const {return this->x;}; + + /** @brief Get raw Y component without normalization. */ dataType getRawY() const {return this->y;}; - - bool epsilonEquals(const UnitVector2D& other, double epsilon); -private: - bool dirty; - dataType x; - dataType y; - + /** + * @brief Check equality within epsilon tolerance. + * @param other The vector to compare. + * @param epsilon The tolerance threshold. + * @return True if both components differ by less than epsilon. + */ + bool epsilonEquals(const UnitVector2D& other, double epsilon); +private: + bool dirty; ///< Whether normalization is needed + dataType x; ///< X component + dataType y; ///< Y component }; template @@ -79,8 +112,8 @@ void UnitVector2D::normalize() dataType norminverse = dataType(1)/sqrt(this->x * this->x + this->y * this->y); x *= norminverse; y *= norminverse; - } - dirty = false; + } + dirty = false; } } @@ -91,7 +124,7 @@ void UnitVector2D::setX(dataType _x) { this->x = _x; markAsDirty(); - } + } } template @@ -101,21 +134,9 @@ void UnitVector2D::setY(dataType _y) { this->y = _y; markAsDirty(); - } + } } -// template -// dataType UnitVector2D::getRawX() -// { -// return this->x; -// } - -// template -// dataType UnitVector2D::getRawY() -// { -// return this->y; -// } - template bool UnitVector2D:: epsilonEquals(const UnitVector2D& other, double epsilon) { @@ -124,4 +145,4 @@ bool UnitVector2D:: epsilonEquals(const UnitVector2D& other, _LJH_EUCLID_LIB_END -#endif \ No newline at end of file +#endif diff --git a/include/Heuclid/euclid/tuple2D/Vector2D.h b/include/Heuclid/euclid/tuple2D/Vector2D.h index 7a2745d..7484a9d 100644 --- a/include/Heuclid/euclid/tuple2D/Vector2D.h +++ b/include/Heuclid/euclid/tuple2D/Vector2D.h @@ -1,3 +1,9 @@ +/** + * @file Vector2D.h + * @brief 2D vector with arithmetic operations. + * @author Junhang Lai (赖俊杭) + */ + #pragma once #ifndef __VECTOR__2D__ #define __VECTOR__2D__ @@ -6,68 +12,49 @@ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN + /** - * A 2D vector represents a physical quantity with a magnitude and a direction in the XY-plane. For - * instance, it can be used to represent a 2D velocity, force, or translation from one 2D point to - * another. + * @brief A 2D vector representing magnitude and direction on the XY-plane. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Can represent physical quantities such as velocity, force, or displacement + * in 2D space. */ template class Vector2D { public: + /** @brief Default constructor. Initializes to zero vector. */ Vector2D():x(dataType(0)),y(dataType(0)){}; + + /** @brief Construct from x and y components. */ Vector2D(dataType _x, dataType _y):x(_x),y(_y){}; + + /** @brief Copy constructor. */ Vector2D(const Vector2D& other):x(other.x),y(other.y){}; - void setX(const dataType& _x){if(this->x!=_x) this->x = _x;}; - void setY(const dataType& _y){if(this->y!=_y) this->y = _y;}; + /** @name Getters */ + ///@{ dataType getX() const {return this->x;}; dataType getY() const {return this->y;}; + ///@} + /** @name Setters */ + ///@{ + void setX(const dataType& _x){if(this->x!=_x) this->x = _x;}; + void setY(const dataType& _y){if(this->y!=_y) this->y = _y;}; + ///@} + + /** @brief Equality comparison. */ bool operator==(const Vector2D& other) const {return (this->x == other.x&&this->y==other.y);}; - private: - dataType x; - dataType y; + dataType x; ///< X component + dataType y; ///< Y component }; -// template -// Vector2D::Vector2D(const Vector2D& other) -// { -// this->x = other.x; -// this->y = other.y; -// } - -// template -// void Vector2D::setX(const dataType& _x) -// { -// if(this->x != _x) -// this->x = _x; -// } - -// template -// void Vector2D::setY(const dataType& _y) -// { -// if(this->y != _y) -// this->y = _y; -// } - -// template -// dataType Vector2D::getX() -// { -// return this->x; -// } - -// template -// dataType Vector2D::getY() -// { -// return this->y; -// } - - - _LJH_EUCLID_LIB_END #endif diff --git a/include/Heuclid/euclid/tuple3D/Point3D.h b/include/Heuclid/euclid/tuple3D/Point3D.h index 1f19b72..aa4a06f 100644 --- a/include/Heuclid/euclid/tuple3D/Point3D.h +++ b/include/Heuclid/euclid/tuple3D/Point3D.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file Point3D.h + * @brief 3D point representation with arithmetic operations. + * @author Junhang Lai (赖俊杭) + */ #ifndef __Point__3D__ #define __Point__3D__ @@ -8,35 +13,70 @@ _LJH_EUCLID_LIB_BEGIN /** - * A 3D point represents the 3D coordinates of a location in space. - *

- * */ + * @brief A 3D point representing coordinates in 3D space. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Provides 3D point operations including arithmetic (+, -, *, /), + * distance computation, and Eigen::Matrix interoperability. + */ template class Point3D { public: + /** @brief Default constructor. Initializes to origin (0, 0, 0). */ Point3D():x(dataType(0)),y(dataType(0)),z(dataType(0)){}; + /** @brief Construct from x, y, z coordinates. */ Point3D(dataType _x, dataType _y, dataType _z):x(_x),y(_y),z(_z){}; + /** @brief Copy constructor. */ Point3D(const Point3D& other):x(other.x),y(other.y),z(other.z){}; + /** @name Getters */ + ///@{ inline dataType getX() const {return this->x;}; inline dataType getY() const {return this->y;}; inline dataType getZ() const {return this->z;}; + ///@} + + /** @name Setters */ + ///@{ inline void setX(dataType _x) {this->x = _x;}; inline void setY(dataType _y) {this->y = _y;}; inline void setZ(dataType _z) {this->z = _z;}; inline void setPoint3D(const dataType& _x,const dataType& _y,const dataType& _z) {this->x = _x;this->y = _y;this->z = _z;}; inline void setPoint3D(const Point3D& other) {this->x =other.x;this->y = other.y;this->z = other.z;}; + ///@} + /** @name Comparison operators */ + ///@{ inline bool operator==(const Point3D& other) const {return (this->getX()==other.getX()&& this->getY()==other.getY()&& this->getZ()==other.getZ());}; + ///@} + /** + * @brief Check equality within epsilon tolerance (component-wise). + * @param other The point to compare. + * @param epsilon The tolerance threshold. + */ bool epsilonEquals(const Point3D& other, const double& epsilon); + + /** + * @brief Check geometric equality (Euclidean distance). + * @param other The point to compare. + * @param epsilon The distance threshold. + */ bool geometricallyEquals(const Point3D& other, const double& epsilon); + + /** + * @brief Check if point is at origin within epsilon. + * @param epsilon The tolerance threshold. + */ bool epsilonZero(const double& epsilon); + + /** @brief Assignment operator. */ inline void operator= (const Point3D& other) {this->x = other.x;this->y = other.y;this->z = other.z;}; // 重载运算符 + - * / diff --git a/include/Heuclid/euclid/tuple3D/UnitVector3D.h b/include/Heuclid/euclid/tuple3D/UnitVector3D.h index a114519..1df820d 100644 --- a/include/Heuclid/euclid/tuple3D/UnitVector3D.h +++ b/include/Heuclid/euclid/tuple3D/UnitVector3D.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file UnitVector3D.h + * @brief 3D unit vector with automatic normalization. + * @author Junhang Lai (赖俊杭) + */ #ifndef __UNIT__VECTOR__3D__ #define __UNIT__VECTOR__3D__ @@ -8,16 +13,15 @@ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN + /** - * Implementation for a 3 dimensional unit-length vector. - * - * This unit vector shares the same API as a regular vector 3D while ensuring it is normalized when - * accessing directly or indirectly its individual components, i.e. when invoking either - * {@link #getX()}, {@link #getY()}, or {@link #getZ()}. + * @brief A 3D unit-length vector with lazy normalization. + * + * @tparam dataType The scalar type (e.g., double, float). * - * When the values of this vector are set to zero, the next time it is normalized it will be reset - * to (1.0, 0.0, 0.0). - * */ + * Same as UnitVector2D but in 3D. When set to zero, the next normalization + * resets to (1, 0, 0). + */ template class UnitVector3D { diff --git a/include/Heuclid/euclid/tuple3D/Vector3D.h b/include/Heuclid/euclid/tuple3D/Vector3D.h index ff947bb..7d60b73 100644 --- a/include/Heuclid/euclid/tuple3D/Vector3D.h +++ b/include/Heuclid/euclid/tuple3D/Vector3D.h @@ -1,3 +1,9 @@ +/** + * @file Vector3D.h + * @brief 3D vector with arithmetic operations. + * @author Junhang Lai (赖俊杭) + */ + #pragma once #ifndef __VECTOR__3D__ #define __VECTOR__3D__ @@ -6,35 +12,55 @@ #define _LJH_EUCLID_LIB_END }} _LJH_EUCLID_LIB_BEGIN + /** - * A 3D vector represents a physical quantity with a magnitude and a direction in the XY-plane. For - * instance, it can be used to represent a 3D velocity, force, or translation from one 3D point to - * another. + * @brief A 3D vector representing magnitude and direction in 3D space. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Can represent physical quantities such as velocity, force, or displacement + * in 3D space. + * + * @note This class is minimal. Consider extending with arithmetic operators + * as needed (see Point3D for reference). */ template class Vector3D { public: + /** @brief Default constructor. Initializes to zero vector. */ Vector3D():x(dataType(0)),y(dataType(0)),z(dataType(0)){}; + + /** @brief Construct from x, y, z components. */ Vector3D(dataType _x, dataType _y, dataType _z):x(_x),y(_y),z(_z){}; + + /** @brief Copy constructor. */ Vector3D(const Vector3D& other):x(other.x),y(other.y),z(other.z){}; - void setX(const dataType& _x){if(this->x!=_x) this->x = _x;}; - void setY(const dataType& _y){if(this->y!=_y) this->y = _y;}; - void setZ(const dataType& _z){if(this->z!=_z) this->z = _z;}; + /** @name Getters */ + ///@{ dataType getX() const {return this->x;}; dataType getY() const {return this->y;}; dataType getZ() const {return this->z;}; + ///@} - bool operator==(const Vector2D& other) const + /** @name Setters */ + ///@{ + void setX(const dataType& _x){if(this->x!=_x) this->x = _x;}; + void setY(const dataType& _y){if(this->y!=_y) this->y = _y;}; + void setZ(const dataType& _z){if(this->z!=_z) this->z = _z;}; + ///@} + + /** @brief Equality comparison. */ + bool operator==(const Vector3D& other) const {return (this->x == other.x&&this->y==other.y&&this->z==other.z);}; - + private: - dataType x; - dataType y; - dataType z; + dataType x; ///< X component + dataType y; ///< Y component + dataType z; ///< Z component }; _LJH_EUCLID_LIB_END -#endif \ No newline at end of file +#endif diff --git a/include/Heuclid/euclid/tuple4D/Quaternion.h b/include/Heuclid/euclid/tuple4D/Quaternion.h index 3d226bb..730e959 100644 --- a/include/Heuclid/euclid/tuple4D/Quaternion.h +++ b/include/Heuclid/euclid/tuple4D/Quaternion.h @@ -1,15 +1,23 @@ #pragma once +/** + * @file Quaternion.h + * @brief Quaternion representation with Euler angle conversion. + * @author Junhang Lai (赖俊杭) + */ #include #include _LJH_EUCLID_LIB_BEGIN /** - * Class used to represent unit-quaternions - * which are used to represent 3D orientations. - * - * s + xi + yj + zk - * - * @author Lai Junhang + * @brief Unit quaternion for representing 3D orientations. + * + * @tparam dataType The scalar type (e.g., double, float). + * + * Represents rotations as s + xi + yj + zk where the quaternion is always + * normalized. Supports Euler angle (ZYX) conversion, conjugation, and + * quaternion multiplication. + * + * Euler angles follow the ZYX convention (yaw-pitch-roll). */ template class Quaternion diff --git a/include/Heuclid/geometry/ConvexHull2D.h b/include/Heuclid/geometry/ConvexHull2D.h index 4188c6f..316ee1b 100644 --- a/include/Heuclid/geometry/ConvexHull2D.h +++ b/include/Heuclid/geometry/ConvexHull2D.h @@ -1,4 +1,9 @@ +/** + * @file ConvexHull2D.h + * @brief 2D convex hull computation (Graham scan, Gift wrapping). + * @author Junhang Lai (赖俊杭) + */ #include #include #include @@ -46,15 +51,23 @@ class ConvexHull2D }; + /** @brief Compute convex hull and convert to half-space form A*x <= b. */ void calculateHalfspaceForm(CONVEXHULL_METHOD method); + /** @brief Load vertices from two rectangles (for bipedal support polygon). */ void loadRectangleVertex(Rectangle rec1, Rectangle rec2); + /** @brief Load a custom set of 2D vertices. */ void loadVertex(const std::vector>& _pointList); - auto &getA_Matrix() const{return this->A_Matrix;}; - auto &getb_Matrix() const{return this->b_Matrix;}; - auto &getAb_Matrix()const{return this->Ab_Matrix;}; - auto &getNumofVertex()const{return this->numOfPoints;}; - auto &getPointList() const{return this->pointList;}; + /** @brief Get the half-space inequality matrix A (A*x <= b). */ + const Eigen::Matrix& getA_Matrix() const{return this->A_Matrix;}; + /** @brief Get the half-space inequality vector b (A*x <= b). */ + const Eigen::Vector& getb_Matrix() const{return this->b_Matrix;}; + /** @brief Get the combined [A | b] matrix. */ + const Eigen::Matrix& getAb_Matrix()const{return this->Ab_Matrix;}; + /** @brief Get the number of hull vertices. */ + int getNumofVertex()const{return this->numOfPoints;}; + /** @brief Get the vertex point list. */ + const std::vector>& getPointList() const{return this->pointList;}; private: int numOfPoints; std::vector> pointList; @@ -116,7 +129,7 @@ void ConvexHull2D::computeConvexHullbyGraham_scan() // Swap the lowest point with the first point in the array std::swap(this->pointList[0], this->pointList[lowestIndex]); - for(auto & point = this->pointList.begin() +1 ; point != this->pointList.end();point++) + for(auto point = this->pointList.begin() +1 ; point != this->pointList.end();point++) { point->setX(point->getX() - this->pointList[0].getX()); point->setY(point->getY() - this->pointList[0].getY()); @@ -126,7 +139,7 @@ void ConvexHull2D::computeConvexHullbyGraham_scan() // Sort the points based on their polar angle with respect to the lowest point std::sort(this->pointList.begin() + 1, this->pointList.end(), comparePoints); - for(auto & point = this->pointList.begin() +1 ; point != this->pointList.end();point++) + for(auto point = this->pointList.begin() +1 ; point != this->pointList.end();point++) { point->setX(point->getX() + this->pointList[0].getX()); point->setY(point->getY() + this->pointList[0].getY()); diff --git a/include/Heuclid/geometry/ConvexPolygon2D.h b/include/Heuclid/geometry/ConvexPolygon2D.h index dad15fe..e0e12a9 100644 --- a/include/Heuclid/geometry/ConvexPolygon2D.h +++ b/include/Heuclid/geometry/ConvexPolygon2D.h @@ -1,9 +1,15 @@ #pragma once +/** + * @file ConvexPolygon2D.h + * @brief 2D convex polygon representation. + * @author Junhang Lai (赖俊杭) + */ #include #include #include _LJH_EUCLID_LIB_BEGIN +/** @brief A 2D convex polygon defined by its vertex buffer. */ class ConvexPolygon2D { public: diff --git a/include/Heuclid/geometry/Line2D.h b/include/Heuclid/geometry/Line2D.h index 32c8593..73e93bb 100644 --- a/include/Heuclid/geometry/Line2D.h +++ b/include/Heuclid/geometry/Line2D.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file Line2D.h + * @brief 2D line representation (point-direction form). + * @author Junhang Lai (赖俊杭) + */ #include #include #include @@ -9,6 +14,7 @@ _LJH_EUCLID_LIB_BEGIN +/** @brief A 2D line in point-direction form (origin + direction vector). */ class Line2D { private: diff --git a/include/Heuclid/geometry/Pose2D.h b/include/Heuclid/geometry/Pose2D.h index 37d75a8..3101dfd 100644 --- a/include/Heuclid/geometry/Pose2D.h +++ b/include/Heuclid/geometry/Pose2D.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file Pose2D.h + * @brief 2D pose (position + orientation). + * @author Junhang Lai (赖俊杭) + */ #ifndef __Pose__2D__ #define __Pose__2D__ @@ -14,6 +19,7 @@ _LJH_EUCLID_LIB_BEGIN * A {@code Pose2D} represents a position and orientation in the XY-plane. */ template +/** @brief A 2D pose (position + orientation). */ class Pose2D { private: diff --git a/include/Heuclid/geometry/Pose3D.h b/include/Heuclid/geometry/Pose3D.h index 663ac62..704d9b8 100644 --- a/include/Heuclid/geometry/Pose3D.h +++ b/include/Heuclid/geometry/Pose3D.h @@ -1,4 +1,9 @@ #pragma once +/** @brief + * @file Pose3D.h + * @brief 3D pose (position + quaternion orientation). + * @author Junhang Lai (赖俊杭) + */ #ifndef __Pose__3D__ #define __Pose__3D__ @@ -9,7 +14,7 @@ _LJH_EUCLID_LIB_BEGIN -/** +/** @brief * A {@code Pose3D} represents a position and orientation in 3 dimensions. */ template diff --git a/include/Heuclid/geometry/curves/Func.h b/include/Heuclid/geometry/curves/Func.h index 8187705..7f9c009 100644 --- a/include/Heuclid/geometry/curves/Func.h +++ b/include/Heuclid/geometry/curves/Func.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file Func.h + * @brief Template function and Bézier curve classes. + * @author Junhang Lai (赖俊杭) + */ #include #include diff --git a/include/Heuclid/geometry/tools/HeuclidGeometryTools.h b/include/Heuclid/geometry/tools/HeuclidGeometryTools.h index b303dde..3841011 100644 --- a/include/Heuclid/geometry/tools/HeuclidGeometryTools.h +++ b/include/Heuclid/geometry/tools/HeuclidGeometryTools.h @@ -1,4 +1,9 @@ #pragma once +/** + * @file HeuclidGeometryTools.h + * @brief Geometry utility functions (line intersection, etc.). + * @author Junhang Lai (赖俊杭) + */ #include #include #include @@ -12,6 +17,13 @@ #endif _LJH_EUCLID_LIB_BEGIN + +/** + * @brief Static utility functions for 2D geometric computations. + * + * Provides line-side tests, point-on-line checks, and other geometric + * predicates with configurable epsilon tolerances. + */ class HeuclidGeometryTools { private: diff --git a/include/Heuclid/geometry/tools/HeuclidPolygonTools.h b/include/Heuclid/geometry/tools/HeuclidPolygonTools.h index 9fd02bf..21ffa64 100644 --- a/include/Heuclid/geometry/tools/HeuclidPolygonTools.h +++ b/include/Heuclid/geometry/tools/HeuclidPolygonTools.h @@ -1,4 +1,9 @@ #include +/** + * @file HeuclidPolygonTools.h + * @brief Polygon utility functions. + * @author Junhang Lai (赖俊杭) + */ #include #include @@ -6,10 +11,12 @@ #define NUM_INEQUAL_VERTEX -2 #define CHECK_CORRECT 0 _LJH_EUCLID_LIB_BEGIN + /** - * This class provides a variety of tools to perform operations with polygons. + * @brief Static utility functions for polygon operations. * - * @author Lai Junhang + * Provides edge intersection checks, point-in-polygon tests, and other + * polygon-specific geometric predicates. */ class HeuclidGeometryPolygonTools { diff --git a/include/Heuclid/title/Title.h b/include/Heuclid/title/Title.h index 2a8ab4b..65e3389 100644 --- a/include/Heuclid/title/Title.h +++ b/include/Heuclid/title/Title.h @@ -1,4 +1,9 @@ +/** + * @file Title.h + * @brief Namespace definition macros for Heuclid library. + * @author Junhang Lai (赖俊杭) + */ // Set the Proper LibName of the Namespace #ifndef _LJH_EUCLID_LIB_BEGIN #define _LJH_EUCLID_LIB_BEGIN namespace ljh{namespace heuclid{ diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 68659b1..4783eb3 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1,38 +1,43 @@ -# cmake_minimum_required(VERSION 3.0) -project(HeuclidTest) - -# add_compile_options(/MT /O2) - -# find_package(Heuclid REQUIRED) - -# # include_directories(${HEUCLID_INCLUDE_DIRS}) -# message("include ${HEUCLID_INCLUDE_DIRS}") -# set(BUILD_TEST_LJH 1) - -# if(${BUILD_TEST_LJH}) -# message("--[Test] Build Heuclid basic test!") -# add_executable(test test.cpp) -# find_package(matplotlib_cpp REQUIRED) -# target_link_libraries(test ${matplotlib_LIBS} Heuclid.lib) -# endif() - - -# 20230612 reconstruct heuclid test with googletest frame -set(Heuclid_gtest_list - TestConvexHull2D - TestBeizer +# +# Heuclid Tests +# +# NOTE: Heuclid is transitioning to header-only. Until all .cpp implementations +# are moved inline to headers, tests link against the source files directly. +# + +# Find GoogleTest +find_package(GTest QUIET) + +if(NOT GTest_FOUND) + message(STATUS "GoogleTest not found - fetching from GitHub") + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY "https://github.com/google/googletest.git" + GIT_TAG "v1.14.0" + GIT_SHALLOW TRUE ) - -foreach(NAME IN LISTS Heuclid_gtest_list) - if(MSVC) - find_package(GTest REQUIRED) - include(GoogleTest) - add_executable(${NAME} ${NAME}.cpp Foot/FootPolygon.cpp ../Heuclid/geometry/ConvexPolygon2D.cpp ../Heuclid/euclid/tools/HeuclidCoreTool.cpp) - target_link_libraries(${NAME} GTest::gtest) - target_compile_options(${NAME} PUBLIC /MT) - gtest_discover_tests(${NAME}) - endif() -endforeach() - -target_include_directories(TestConvexHull2D PUBLIC ./include) -target_include_directories(TestConvexHull2D PUBLIC ./src/Test/Foot) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) + include(GoogleTest) +endif() + +# Heuclid source files (until full header-only migration) +set(HEUCLID_SOURCES + ../Heuclid/euclid/orientation/Orientation2D.cpp + ../Heuclid/euclid/tools/HeuclidCoreTool.cpp + ../Heuclid/geometry/ConvexPolygon2D.cpp + ../Heuclid/geometry/Line2D.cpp + ../Heuclid/geometry/tools/HeuclidGeometryTools.cpp + ../Heuclid/geometry/tools/HeuclidPolygonTools.cpp +) + +# Test: ConvexHull2D +add_executable(TestConvexHull2D TestConvexHull2D.cpp Foot/FootPolygon.cpp ${HEUCLID_SOURCES}) +target_link_libraries(TestConvexHull2D PRIVATE heuclid GTest::gtest_main) +gtest_discover_tests(TestConvexHull2D) + +# Test: Bezier curves +add_executable(TestBeizer TestBeizer.cpp ${HEUCLID_SOURCES}) +target_link_libraries(TestBeizer PRIVATE heuclid GTest::gtest_main) +gtest_discover_tests(TestBeizer)