February 28, 2025

About

I want to read STL files in C++, but there seem to be several options.

NameLicenseCommercial Use
AssimpBSD 3-ClausePossible
VCG LibraryGPL or LGPLRestricted
libiglMPL 2.0 or GPLPossible
Open3DMIT LicensePossible
CGALGPL or CommercialPaid

Assimp, Open3D, and libigl might be good choices.
However, Assimp took an incredibly long time to build, and I lost all motivation to proceed further. Open3D was quite troublesome to build with CMake, encountering various errors related to Python bindings and the GUI. Among them, the Python binding errors seem to stem from standard libraries no longer used after Python 3.8. Libraries with many dependencies are indeed a hassle to manage.

I tried libigl a little, and it worked smoothly. It simply reads the vertices and face information of an STL file, but it worked seamlessly with Eigen. This might be thanks to the stable performance of libraries like Eigen.
Anyway, here’s a snippet for reference

Main.cpp

Some of the part is not so cool in the code because it uses ‘fopen’ and ‘FILE’.

#include <CLI/CLI.hpp>
#include <iostream>
#include <igl/readSTL.h>
#include <Eigen/Core>
#include <iostream>


int main(int argc, char** argv){
    CLI::App app("Example CLI");
    std::string stl_path = "./test.stl";
    app.add_option("-s,--stl", stl_path, "Set Path for stl file");

    CLI11_PARSE(app, argc, argv);
    std::cout << "stl_path" << stl_path << std::endl;
    
    FILE* stl_file = fopen(stl_path.c_str(), "rb");
    if (!stl_file) {
        std::cerr << "Failed to open STL file: " << stl_path << std::endl;
        return 1;
    }

    Eigen::MatrixXd V;  // Coordinates of Vertices
    Eigen::MatrixXi F;  // Indeces of Faces
    Eigen::MatrixXd N;  // NOrmal

    if (!igl::readSTL(stl_file, V, F, N)) {
        std::cerr << "Failed to load STL file: " << stl_path << std::endl;
        #fclose(stl_file);
        return 1;
    }
    #fclose(stl_file);

    std::cout << "Successfully loaded: " << stl_path << std::endl;
    std::cout << "Vertices: " << V.rows() << std::endl;
    std::cout << "Triangles: " << F.rows() << std::endl;
    std::cout << "Normals: " << N.rows() << std::endl;

    return 0;
}

cmake_minimum_required(VERSION 3.14)

project(my_project)

set(CMAKE_CXX_STANDARD 17)

include(FetchContent)
FetchContent_Declare(
    CLI11
    GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
    GIT_TAG        v2.3.2
)
FetchContent_MakeAvailable(CLI11)

FetchContent_Declare(
    Eigen
    GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
    GIT_TAG 3.4.0 
)
FetchContent_MakeAvailable(Eigen)

FetchContent_Declare(
    Libigl
    GIT_REPOSITORY https://github.com/libigl/libigl.git
    GIT_TAG v2.4.0
)
FetchContent_MakeAvailable(Libigl)


add_executable(my_project src/main.cpp)
target_link_libraries(my_project PRIVATE CLI11 igl::core Eigen3::Eigen)

target_include_directories(my_project PRIVATE
    ${Eigen_SOURCE_DIR}
    ${Libigl_SOURCE_DIR}/include
)