diff --git a/README.md b/README.md index deb48f1..e6c9ecc 100644 --- a/README.md +++ b/README.md @@ -29,19 +29,17 @@ API, file formats and command‑line interface are all subject to change. ```bash git clone https://codeberg.org/user2595/ConformalLabpp -cd conformallabpp -git submodule update --init --recursive +cd conformallabpp/code ``` ### Configure and build ```bash -cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -cmake --build build -Run a simple example +cmake -S . -B build && cmake --build build ``` + +### Run the binare ```bash -# ./build/bin/conformallabpp -(Example command, to be adapted once the first tools are implemented.) + ./bin/conformallab_core --input ./data/off/simple_cupe.off ``` ### License conformallabpp is released under the MIT License (see LICENSE). diff --git a/code/.gitignore b/code/.gitignore index 22caeec..264b0e8 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -8,12 +8,14 @@ build/ # Dependencies: Tarballs immer committen, entpackte ignorieren # exclude alle subdirs von depd without excluding the tarballs and single_includes -deps/*/*/ -!deps/tarballs/*.tar.* +deps/* +!deps/tarballs !deps/single_includes/ -!deps/Cmakelists.txt +!deps/CMakeLists.txt +bin + # IDEs .vscode/ .idea/ diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 19b4c01..e2faa85 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.20) set(PROJECT_NAME "conformallab_core") -project(${PROJECT_NAME} LANGUAGES CXX) +project(${PROJECT_NAME} LANGUAGES C CXX) message(STATUS "Configuring ${PROJECT_NAME}...") @@ -32,8 +32,11 @@ endif() add_subdirectory(deps) +add_subdirectory(deps/glfw-3.4) + + # --------- Executable --------- -add_executable(${PROJECT_NAME} src/apps/conformallab_cli.cpp src/apps/unwarp_job.cpp) +add_executable(${PROJECT_NAME} src/apps/v0/conformallab_cli.cpp ) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include @@ -42,9 +45,28 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/deps/CGAL-6.1.1/include ${CMAKE_CURRENT_SOURCE_DIR}/deps/boost_1_90_0/ ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-2.6.0/include + ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/include +) + + +add_library(glad STATIC + ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/src/glad.c +) +target_include_directories(glad PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/include +) + +target_compile_definitions(${PROJECT_NAME} PRIVATE + CGAL_DISABLE_GMP + CGAL_DISABLE_MPFR ) # Output-Ordner set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin + ) +target_link_libraries(${PROJECT_NAME} + PRIVATE glad glfw +) + diff --git a/code/data/off/simple_cupe.off b/code/data/off/simple_cupe.off new file mode 100644 index 0000000..cabe7ba --- /dev/null +++ b/code/data/off/simple_cupe.off @@ -0,0 +1,16 @@ +OFF +8 6 0 +-0.500000 -0.500000 0.500000 +0.500000 -0.500000 0.500000 +-0.500000 0.500000 0.500000 +0.500000 0.500000 0.500000 +-0.500000 0.500000 -0.500000 +0.500000 0.500000 -0.500000 +-0.500000 -0.500000 -0.500000 +0.500000 -0.500000 -0.500000 +4 0 1 3 2 +4 2 3 5 4 +4 4 5 7 6 +4 6 7 1 0 +4 1 7 5 3 +4 6 0 2 4 \ No newline at end of file diff --git a/code/deps/Cmakelists.txt b/code/deps/Cmakelists.txt index 19d39fc..d6a0910 100644 --- a/code/deps/Cmakelists.txt +++ b/code/deps/Cmakelists.txt @@ -7,13 +7,21 @@ function(setup_dependency NAME SUBDIR) if(NOT TARBALL) message(FATAL_ERROR "❌ No '${NAME}*.tar.*' in deps/tarballs/") else() - - message(STATUS "${CMAKE_COMMAND} ${TARBALL}" ) - execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xf "${TARBALL}" "${NAME}/${SUBDIR}" RESULT_VARIABLE TAR_STATUS WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) - message(STATUS "Extracting ${NAME}... Output: ${TAR_OUTPUT} Status: ${TAR_STATUS}") - if(NOT TAR_STATUS EQUAL 0) - message(FATAL_ERROR "❌ Extract failed: ${NAME}") - endif() + message(STATUS "${CMAKE_COMMAND} ${TARBALL}" ) + + if(SUBDIR STREQUAL "") + execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xf "${TARBALL}" RESULT_VARIABLE TAR_STATUS WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) + message(STATUS "Extracting ${NAME}... Output: ${TAR_OUTPUT} Status: ${TAR_STATUS}") + if(NOT TAR_STATUS EQUAL 0) + message(FATAL_ERROR "❌ Extract failed: ${NAME}") + endif() + else() + execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xf "${TARBALL}" "${NAME}/${SUBDIR}" RESULT_VARIABLE TAR_STATUS WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) + message(STATUS "Extracting ${NAME}... Output: ${TAR_OUTPUT} Status: ${TAR_STATUS}") + if(NOT TAR_STATUS EQUAL 0) + message(FATAL_ERROR "❌ Extract failed: ${NAME}") + endif() + endif() endif() else() message(STATUS "✅ ${NAME} already exists, skipping extraction.") @@ -24,5 +32,6 @@ setup_dependency("CGAL-6.1.1" "include" ) setup_dependency("eigen-3.4.0" "Eigen" ) setup_dependency("boost_1_90_0" "boost" ) setup_dependency("libigl-2.6.0" "include" ) - +setup_dependency("libigl-glad" "" ) +setup_dependency("glfw-3.4" "" ) diff --git a/code/deps/tarballs/glfw-3.4.tar.gz b/code/deps/tarballs/glfw-3.4.tar.gz new file mode 100644 index 0000000..ba5209a Binary files /dev/null and b/code/deps/tarballs/glfw-3.4.tar.gz differ diff --git a/code/deps/tarballs/libigl_v2.6.0.tar.gz b/code/deps/tarballs/libigl-2.6.0.tar.gz similarity index 100% rename from code/deps/tarballs/libigl_v2.6.0.tar.gz rename to code/deps/tarballs/libigl-2.6.0.tar.gz diff --git a/code/deps/tarballs/libigl-glad.tar.gz b/code/deps/tarballs/libigl-glad.tar.gz new file mode 100644 index 0000000..7ed2a3b Binary files /dev/null and b/code/deps/tarballs/libigl-glad.tar.gz differ diff --git a/code/src/apps/v0/conformallab_cli.cpp b/code/src/apps/v0/conformallab_cli.cpp new file mode 100644 index 0000000..d99cd14 --- /dev/null +++ b/code/src/apps/v0/conformallab_cli.cpp @@ -0,0 +1,93 @@ +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +using Kernel = CGAL::Simple_cartesian; +using Point = Kernel::Point_3; +using Mesh = CGAL::Surface_mesh; +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char* argv[]) +{ + CLI::App app{"demo of conformallab"}; + std::string input_file; + std::string output_file; // default output file name + + app.add_option("-i,--input", input_file, "Input OFF file")->required(); + app.add_option("-o,--output", output_file, "Output OFF file (optional)"); + CLI11_PARSE(app, argc, argv); + + if (input_file.empty()) { + std::cerr << "Input file is required.\n"; + return EXIT_FAILURE; + } + + if (input_file.substr(input_file.find_last_of('.') + 1) != "off") { + std::cerr << "Unsupported file format. Please provide an OFF file.\n"; + return EXIT_FAILURE; + } + + Mesh surface_mesh; + if (!CGAL::IO::read_polygon_mesh(input_file, surface_mesh) || surface_mesh.is_empty()) { + std::cerr << "Invalid input file: " << input_file << "\n"; + return EXIT_FAILURE; + } + + // #TODO: later: here we would call the unwrapping code, e.g.: + // UnwrapSettings settings; + // settings.target_geometry = TargetGeometry::Euclidean; + // UnwrapJob job(surface_mesh, settings); + // auto result = job.run(); + // Mesh unwrapped = result.surface_unwrapped; + + + // CGAL -> libigl + PMP::triangulate_faces(surface_mesh); + //todo : we should check if the mesh is already triangulated, and only call this if it isn't, to avoid unnecessary processing. CGAL::Polygon_mesh_processing::is_triangulated() can be used for this check. + Eigen::MatrixXd Vertices; + Eigen::MatrixXi Faces; + Vertices.resize(surface_mesh.number_of_vertices(), 3); + Faces.resize(surface_mesh.number_of_faces(), 3); + + for (auto v : surface_mesh.vertices()) { + const auto& p = surface_mesh.point(v); + Vertices(v.idx(), 0) = p.x(); + Vertices(v.idx(), 1) = p.y(); + Vertices(v.idx(), 2) = p.z(); + } + + int f_i = 0; + for (auto f : surface_mesh.faces()) { + int k = 0; + for (auto hv : CGAL::halfedges_around_face(surface_mesh.halfedge(f), surface_mesh)) { + auto v = surface_mesh.target(hv); + Faces(f_i, k) = v.idx(); + ++k; + } + ++f_i; + } + + igl::opengl::glfw::Viewer viewer; + viewer.data().set_mesh(Vertices, Faces); + viewer.launch(); + + + + // for now, we just write the input mesh to the output file as a placeholder + if (!output_file.empty() && !CGAL::IO::write_polygon_mesh(output_file, surface_mesh)) { + std::cerr << "Failed to write output file: " << output_file << "\n"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}