├── .gitignore ├── LICENSE ├── example ├── data │ ├── Cat.obj │ ├── K.txt │ ├── images │ │ ├── 0000.png │ │ ├── 0001.png │ │ ├── 0002.png │ │ ├── 0003.png │ │ ├── 0004.png │ │ ├── 0005.png │ │ ├── 0006.png │ │ ├── 0007.png │ │ ├── 0008.png │ │ ├── 0009.png │ │ ├── 0010.png │ │ ├── 0011.png │ │ ├── 0012.png │ │ ├── 0013.png │ │ ├── 0014.png │ │ ├── 0015.png │ │ ├── 0016.png │ │ ├── 0017.png │ │ ├── 0018.png │ │ ├── 0019.png │ │ ├── 0020.png │ │ ├── 0021.png │ │ ├── 0022.png │ │ ├── 0023.png │ │ ├── 0024.png │ │ ├── 0025.png │ │ ├── 0026.png │ │ ├── 0027.png │ │ ├── 0028.png │ │ ├── 0029.png │ │ ├── 0030.png │ │ └── pose.txt │ └── pose.txt └── demo.py ├── readme.md ├── setup.py └── source ├── CMakeLists.txt ├── include └── srt3d │ ├── body.h │ ├── camera.h │ ├── common.h │ ├── model.h │ ├── normal_renderer.h │ ├── normal_viewer.h │ ├── occlusion_renderer.h │ ├── region_modality.h │ ├── renderer.h │ ├── renderer_geometry.h │ ├── tracker.h │ └── viewer.h ├── pysrt3d ├── pysrt3d.cpp ├── pysrt3d.hpp └── virtual_camera.hpp ├── src ├── body.cpp ├── camera.cpp ├── common.cpp ├── model.cpp ├── normal_renderer.cpp ├── normal_viewer.cpp ├── occlusion_renderer.cpp ├── region_modality.cpp ├── renderer.cpp ├── renderer_geometry.cpp ├── tracker.cpp └── viewer.cpp └── third_party ├── pybind11 ├── CMakeLists.txt ├── LICENSE ├── README.rst ├── include │ └── pybind11 │ │ ├── attr.h │ │ ├── buffer_info.h │ │ ├── cast.h │ │ ├── chrono.h │ │ ├── common.h │ │ ├── complex.h │ │ ├── detail │ │ ├── class.h │ │ ├── common.h │ │ ├── descr.h │ │ ├── init.h │ │ ├── internals.h │ │ ├── type_caster_base.h │ │ └── typeid.h │ │ ├── eigen.h │ │ ├── eigen │ │ ├── common.h │ │ ├── matrix.h │ │ └── tensor.h │ │ ├── embed.h │ │ ├── eval.h │ │ ├── functional.h │ │ ├── gil.h │ │ ├── gil_safe_call_once.h │ │ ├── iostream.h │ │ ├── numpy.h │ │ ├── operators.h │ │ ├── options.h │ │ ├── pybind11.h │ │ ├── pytypes.h │ │ ├── stl.h │ │ ├── stl │ │ └── filesystem.h │ │ ├── stl_bind.h │ │ ├── type_caster_pyobject_ptr.h │ │ └── typing.h ├── pybind11 │ ├── __init__.py │ ├── __main__.py │ ├── _version.py │ ├── commands.py │ ├── py.typed │ └── setup_helpers.py ├── setup.cfg ├── setup.py └── tools │ ├── FindCatch.cmake │ ├── FindEigen3.cmake │ ├── FindPythonLibsNew.cmake │ ├── JoinPaths.cmake │ ├── check-style.sh │ ├── cmake_uninstall.cmake.in │ ├── codespell_ignore_lines_from_errors.py │ ├── libsize.py │ ├── make_changelog.py │ ├── pybind11.pc.in │ ├── pybind11Common.cmake │ ├── pybind11Config.cmake.in │ ├── pybind11NewTools.cmake │ ├── pybind11Tools.cmake │ ├── pyproject.toml │ ├── setup_global.py.in │ └── setup_main.py.in └── tiny_obj_loader └── tiny_obj_loader.h /.gitignore: -------------------------------------------------------------------------------- 1 | # python 2 | __pycache__/ 3 | # build 4 | dist 5 | build 6 | *.egg-info/ 7 | *.so 8 | # cache dir 9 | .cache 10 | .test 11 | .vscode 12 | # checkpoint 13 | *.ckpt 14 | 15 | *.meta -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jianxff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/data/K.txt: -------------------------------------------------------------------------------- 1 | 481.34025 0.0 329.4003 2 | 0.0 481.8243 260.3788 3 | 0.000000 0.000000 1.000000 4 | -------------------------------------------------------------------------------- /example/data/images/0000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0000.png -------------------------------------------------------------------------------- /example/data/images/0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0001.png -------------------------------------------------------------------------------- /example/data/images/0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0002.png -------------------------------------------------------------------------------- /example/data/images/0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0003.png -------------------------------------------------------------------------------- /example/data/images/0004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0004.png -------------------------------------------------------------------------------- /example/data/images/0005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0005.png -------------------------------------------------------------------------------- /example/data/images/0006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0006.png -------------------------------------------------------------------------------- /example/data/images/0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0007.png -------------------------------------------------------------------------------- /example/data/images/0008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0008.png -------------------------------------------------------------------------------- /example/data/images/0009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0009.png -------------------------------------------------------------------------------- /example/data/images/0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0010.png -------------------------------------------------------------------------------- /example/data/images/0011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0011.png -------------------------------------------------------------------------------- /example/data/images/0012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0012.png -------------------------------------------------------------------------------- /example/data/images/0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0013.png -------------------------------------------------------------------------------- /example/data/images/0014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0014.png -------------------------------------------------------------------------------- /example/data/images/0015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0015.png -------------------------------------------------------------------------------- /example/data/images/0016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0016.png -------------------------------------------------------------------------------- /example/data/images/0017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0017.png -------------------------------------------------------------------------------- /example/data/images/0018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0018.png -------------------------------------------------------------------------------- /example/data/images/0019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0019.png -------------------------------------------------------------------------------- /example/data/images/0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0020.png -------------------------------------------------------------------------------- /example/data/images/0021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0021.png -------------------------------------------------------------------------------- /example/data/images/0022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0022.png -------------------------------------------------------------------------------- /example/data/images/0023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0023.png -------------------------------------------------------------------------------- /example/data/images/0024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0024.png -------------------------------------------------------------------------------- /example/data/images/0025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0025.png -------------------------------------------------------------------------------- /example/data/images/0026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0026.png -------------------------------------------------------------------------------- /example/data/images/0027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0027.png -------------------------------------------------------------------------------- /example/data/images/0028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0028.png -------------------------------------------------------------------------------- /example/data/images/0029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0029.png -------------------------------------------------------------------------------- /example/data/images/0030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/example/data/images/0030.png -------------------------------------------------------------------------------- /example/data/pose.txt: -------------------------------------------------------------------------------- 1 | 0.78603 -0.587438 0.19255 0.281848 2 | 0.604647 0.795404 -0.0416517 -0.166599 3 | -0.128687 0.149164 0.980401 0.731918 4 | 0 0 0 1 -------------------------------------------------------------------------------- /example/demo.py: -------------------------------------------------------------------------------- 1 | # standard library 2 | from typing import * 3 | from pathlib import Path 4 | import numpy as np 5 | # third party 6 | import cv2 7 | import pysrt3d 8 | 9 | 10 | # fetch images 11 | DATA_DIR = Path(__file__).resolve().parent / 'data' 12 | images_dir = DATA_DIR / 'images' 13 | images = sorted(list(images_dir.glob('*.png'))) 14 | h, w = cv2.imread(str(images[0])).shape[:2] 15 | 16 | # init model 17 | model = pysrt3d.Model( 18 | name="Cat", 19 | model_path=str(DATA_DIR / 'Cat.obj'), 20 | meta_path=str(DATA_DIR / 'Cat.meta'), 21 | unit_in_meter=0.001, # the model was made in 'mm' 22 | threshold_init = 0.0, # no limit while initialization 23 | threshold_track = 0.0, # no limit while tracking 24 | kl_threshold = 1.0 25 | ) 26 | 27 | # init tracker 28 | tracker = pysrt3d.Tracker( 29 | imwidth=w, 30 | imheight=h, 31 | K=np.loadtxt(DATA_DIR / 'K.txt', dtype=np.float32) 32 | ) 33 | 34 | # add model to tracker 35 | tracker.add_model(model) 36 | # setup tracker 37 | tracker.setup() 38 | # make renderer 39 | renderer = pysrt3d.Renderer(tracker) 40 | 41 | # set init pose 42 | init_pose = np.loadtxt(DATA_DIR / 'pose.txt') 43 | model.reset_pose(init_pose) 44 | 45 | 46 | for image in images: 47 | # read image 48 | image = cv2.imread(str(image)) 49 | image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 50 | 51 | # tracking iteration 52 | tracker.update(image=image_rgb) 53 | # get tracking info 54 | pose_uv = model.pose_uv 55 | conf = model.conf 56 | 57 | # render normal view 58 | normal_image = renderer.render() 59 | # write tracking info 60 | cv2.putText(normal_image, f"{model.name}: {conf:.2f}", pose_uv, cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) 61 | 62 | cv2.imshow('view', normal_image) 63 | cv2.waitKey(0) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # pysrt3d 2 | 3 | Python binding for [*SRT3D: Region-Based 6DoF Object Tracking*](https://github.com/DLR-RM/3DObjectTracking/tree/master/SRT3D) 4 | 5 | https://github.com/user-attachments/assets/bf9b0102-c6a2-4eba-bd31-6a6ffa3dec50 6 | 7 | ## Modification 8 | #### 1. Automatical body-diameter calculation 9 | You don't need to specify `max_body_diameter` manually, just as [*M3T*](https://github.com/DLR-RM/3DObjectTracking/tree/master/M3T). 10 | 11 | #### 2. Kullback-Leibler divergence based confidence assessment 12 | If the predicted pose is good (close to the reality), the mean value of each correspondence line will be zero (at the center, without offset). We calculate KL divergence for each correspondence line and the optimal one: $\mathcal{N}(0, \sigma_{min}^2)$. 13 | 14 | #### 3. Thresholds for initialization and tracking 15 | We define thresholds for initialization and tracking (you can manually set them), so that you can easily align the object to the virtual one before starting tracking. 16 | 17 | #### 4. Independent multi-model tracking 18 | The confidences are calculated independently. You can easily add models and get their information (pose, conf., etc.). 19 | 20 | 21 | ## Installation 22 | Make sure that you have installed the following packages: 23 | - GLEW 24 | - glfw3 25 | - Eigen3 26 | - OpenCV 3/4 27 | - OpenMP (may have already installed on your system) 28 | 29 | Your compilation environment should support `C++ 17`. 30 | 31 | #### Dependency Instruction 32 | - [method 1] Through system path 33 | ``` 34 | $ sudo apt install libglew-dev libglfw3-dev libeigen3-dev 35 | # BUILD opencv from source code: https://github.com/opencv/opencv 36 | ``` 37 | 38 | - [method 2] Under conda env 39 | ``` 40 | $ conda activate ${YOUR_ENV_NAME} 41 | $ conda install glew glfw eigen libopencv 42 | ``` 43 | 44 | - Other dependencies for `demo.py` 45 | ``` 46 | pip install numpy 47 | pip install opencv-python 48 | ``` 49 | 50 | #### Package Installation 51 | ``` 52 | cd ${repo_root} 53 | pip install . 54 | ``` 55 | 56 | 57 | ## Demo 58 | \* *The demo data is from [DeepAC](https://github.com/WangLongZJU/DeepAC)*. 59 | ``` 60 | cd ${repo_root}/example 61 | python demo.py 62 | ``` 63 | 64 | 65 | ## Interface 66 | Just follow `example/demo.py` or `source/pysrt3d/pysrt3d.cpp`. 67 | 68 | ## Note 69 | This algorithm is for object tracking only, without global pose estimation. In consequence, an initial pose (4 by 4 matrix under opencv coordinate) must be provided before you start tracking. 70 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | from setuptools import setup, Extension 5 | from setuptools.command.build_ext import build_ext 6 | 7 | class CMakeExtension(Extension): 8 | def __init__(self, name): 9 | super().__init__(name, sources=[]) 10 | 11 | class BuildExt(build_ext): 12 | def run(self): 13 | for ext in self.extensions: 14 | if isinstance(ext, CMakeExtension): 15 | self.build_cmake(ext) 16 | super().run() 17 | 18 | def build_cmake(self, ext): 19 | base_dir = Path(__file__).resolve().parent 20 | os.chdir(base_dir) 21 | build_temp = Path(self.build_temp) 22 | os.makedirs(build_temp, exist_ok=True) 23 | ext_dir = Path(self.get_ext_fullpath(ext.name)).absolute() 24 | os.makedirs(ext_dir.parent, exist_ok=True) 25 | 26 | cmake_args = [ 27 | "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=" + str(ext_dir.parent), 28 | "-DCMAKE_BUILD_TYPE=Release" 29 | ] 30 | 31 | build_args = ["-j6"] 32 | 33 | os.chdir(build_temp) 34 | self.spawn(["cmake", f"{base_dir}/{ext.name}"] + cmake_args) 35 | if not self.dry_run: 36 | self.spawn(["cmake", "--build", "."] + build_args) 37 | os.chdir(base_dir) 38 | 39 | setup( 40 | name='pysrt3d', 41 | ext_modules=[ 42 | CMakeExtension("source") 43 | ], 44 | cmdclass={ 45 | 'build_ext': BuildExt 46 | } 47 | ) 48 | -------------------------------------------------------------------------------- /source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | cmake_policy(SET CMP0072 NEW) 3 | cmake_policy(SET CMP0079 NEW) 4 | 5 | # A Sparse Region-Based 3D Object Tracking Approach for the Real World 6 | # ============================================================================= 7 | project(pysrt3d LANGUAGES CXX C) 8 | 9 | # CXX Standard 10 | # ============================================================================= 11 | set(CMAKE_CXX_STANDARD 17) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | # set(CMAKE_BUILD_TYPE "Release") 14 | 15 | 16 | # Conda Environment 17 | # ============================================================================= 18 | if(DEFINED ENV{CONDA_PREFIX}) 19 | message(STATUS "Conda environment detected: $ENV{CONDA_PREFIX}") 20 | set(CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}") 21 | set(CMAKE_LIBRARY_PATH "$ENV{CONDA_PREFIX}/lib") 22 | set(CMAKE_INSTALL_RPATH "$ENV{CONDA_PREFIX}/lib") 23 | endif() 24 | 25 | 26 | # Python 27 | # ============================================================================= 28 | find_package(PythonInterp REQUIRED) 29 | find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED) 30 | message(STATUS "Found python ${PYTHON_VERSION_STRING} at: ${PYTHON_EXECUTABLE}") 31 | message(STATUS "Python includes: ${PYTHON_INCLUDE_DIRS}") 32 | 33 | 34 | # Libraries 35 | # ============================================================================= 36 | find_package(Eigen3 REQUIRED) 37 | find_package(OpenGL REQUIRED) 38 | find_package(GLEW REQUIRED) 39 | find_package(glfw3 3 REQUIRED) 40 | find_package(OpenCV 4 REQUIRED) 41 | find_package(OpenMP REQUIRED) 42 | if(OpenMP_FOUND) 43 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 44 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 45 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 46 | endif() 47 | 48 | 49 | # Compiler Settings 50 | # ============================================================================= 51 | # Default settings 52 | # set(CMAKE_CXX_VISIBILITY_PRESET hidden) 53 | include(CheckCXXCompilerFlag) 54 | check_cxx_compiler_flag(-march HAS_MARCH) 55 | check_cxx_compiler_flag(-mtune HAS_MTUNE) 56 | if(HAS_MARCH) 57 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") 58 | endif() 59 | if(HAS_MTUNE) 60 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=native") 61 | endif() 62 | 63 | 64 | # Release settings 65 | # check_cxx_compiler_flag(-Ob3 HAS_OB3) 66 | # check_cxx_compiler_flag(-O3 HAS_O3) 67 | # check_cxx_compiler_flag(-Ob2 HAS_OB2) 68 | # check_cxx_compiler_flag(-O2 HAS_O2) 69 | # if (HAS_OB3) 70 | # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ob3") 71 | # elseif (HAS_O3) 72 | # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 73 | # elseif(HAS_OB2) 74 | # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ob2") 75 | # elseif(HAS_O2) 76 | # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") 77 | # endif() 78 | # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG") 79 | 80 | 81 | # PyBind 82 | # ============================================================================= 83 | add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/pybind11) 84 | 85 | # Compiling 86 | # ============================================================================= 87 | FILE(GLOB_RECURSE FILES_CPP "${PROJECT_SOURCE_DIR}/src/*.cpp") 88 | 89 | ## pybind11 module 90 | pybind11_add_module(${PROJECT_NAME} 91 | ${FILES_CPP} 92 | "${PROJECT_SOURCE_DIR}/pysrt3d/pysrt3d.cpp" 93 | ) 94 | 95 | ## include 96 | target_include_directories(${PROJECT_NAME} 97 | PUBLIC 98 | ${PROJECT_SOURCE_DIR}/include 99 | ${PROJECT_SOURCE_DIR}/pysrt3d 100 | ${PROJECT_SOURCE_DIR}/third_party 101 | ${PROJECT_SOURCE_DIR}/third_party/pybind11/include/ 102 | ${PYTHON_INCLUDE_DIRS} 103 | ) 104 | 105 | ## linking 106 | target_link_libraries(${PROJECT_NAME} 107 | PUBLIC 108 | Eigen3::Eigen 109 | PRIVATE 110 | ${OpenCV_LIBS} 111 | OpenGL::GL 112 | GLEW::GLEW 113 | glfw 114 | ) 115 | 116 | ## output 117 | set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "pysrt3d" PREFIX "") 118 | -------------------------------------------------------------------------------- /source/include/srt3d/body.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_BODY_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_BODY_H_ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace srt3d { 17 | 18 | // Class that holds all body information such as name, geometry data, pose, 19 | // and occlusion ids 20 | class Body { 21 | public: 22 | // Constructors and initialization methods 23 | Body(const std::string &name, const std::filesystem::path &geometry_path, 24 | float geometry_unit_in_meter, bool geometry_counterclockwise, 25 | bool geometry_enable_culling, const Transform3fA &geometry2body_pose = Transform3fA::Identity()); 26 | 27 | // Geometry setters 28 | void set_name(const std::string &name); 29 | void set_geometry_path(const std::filesystem::path &geometry_path); 30 | void set_geometry_unit_in_meter(float geometry_unit_in_meter); 31 | void set_geometry_counterclockwise(bool geometry_counterclockwise); 32 | void set_geometry_enable_culling(bool geometry_enable_culling); 33 | // void set_maximum_body_diameter(float maximum_body_diameter); 34 | void set_geometry2body_pose(const Transform3fA &geometry2body_pose); 35 | // bool set_occlusion_id(int occlusion_id); 36 | 37 | // Pose setters 38 | void set_body2world_pose(const Transform3fA &body2world_pose); 39 | void set_world2body_pose(const Transform3fA &world2body_pose); 40 | 41 | // Geometry getters 42 | const std::string &name() const; 43 | const std::filesystem::path &geometry_path() const; 44 | float geometry_unit_in_meter() const; 45 | bool geometry_counterclockwise() const; 46 | bool geometry_enable_culling() const; 47 | float maximum_body_diameter() const; 48 | const Transform3fA &geometry2body_pose() const; 49 | int occlusion_id() const; 50 | 51 | // Pose getters 52 | const Transform3fA &body2world_pose() const; 53 | const Transform3fA &world2body_pose() const; 54 | const Transform3fA &geometry2world_pose() const; 55 | const Transform3fA &world2geometry_pose() const; 56 | 57 | // Auto calculate body diameter 58 | void calculate_maximum_body_diameter(); 59 | 60 | private: 61 | // Geometry data 62 | std::string name_{}; 63 | std::filesystem::path geometry_path_{}; 64 | float geometry_unit_in_meter_ = 1.0f; 65 | bool geometry_counterclockwise_ = true; 66 | bool geometry_enable_culling_ = true; 67 | float maximum_body_diameter_ = 0.0f; 68 | Transform3fA geometry2body_pose_{Transform3fA::Identity()}; 69 | int occlusion_id_ = 0; 70 | 71 | // Pose data 72 | Transform3fA body2world_pose_{Transform3fA::Identity()}; 73 | Transform3fA world2body_pose_{Transform3fA::Identity()}; 74 | Transform3fA geometry2world_pose_{Transform3fA::Identity()}; 75 | Transform3fA world2geometry_pose_{Transform3fA::Identity()}; 76 | }; 77 | 78 | } // namespace srt3d 79 | 80 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_BODY_H_ 81 | -------------------------------------------------------------------------------- /source/include/srt3d/camera.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_CAMERA_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_CAMERA_H_ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace srt3d { 15 | 16 | // Abstract class that defines a camera and functionality to save images. 17 | // It is also able to hold a camera pose. 18 | class Camera { 19 | public: 20 | // Constructor and setup method 21 | Camera(const std::string &name); 22 | virtual bool SetUp() = 0; 23 | 24 | // Setters 25 | void set_name(const std::string &name); 26 | void set_camera2world_pose(const Transform3fA &camera2world_pose); 27 | void set_world2camera_pose(const Transform3fA &world2camera_pose); 28 | void StartSavingImages(const std::filesystem::path &save_directory, 29 | int save_index = 0, 30 | const std::string &save_image_type = "png"); 31 | void StopSavingImages(); 32 | 33 | // Main methods 34 | virtual bool UpdateImage() = 0; 35 | 36 | // Getters 37 | const std::string &name() const; 38 | const cv::Mat &image() const; 39 | const Intrinsics &intrinsics() const; 40 | const Transform3fA &camera2world_pose() const; 41 | const Transform3fA &world2camera_pose() const; 42 | bool save_images() const; 43 | bool set_up() const; 44 | 45 | protected: 46 | // Helper methods 47 | void SaveMetaDataIfDesired() const; 48 | void SaveImageIfDesired(); 49 | 50 | // Variables and data 51 | std::string name_{}; 52 | cv::Mat image_; 53 | Intrinsics intrinsics_{}; 54 | Transform3fA camera2world_pose_{Transform3fA::Identity()}; 55 | Transform3fA world2camera_pose_{Transform3fA::Identity()}; 56 | std::filesystem::path save_directory_{}; 57 | int save_index_{}; 58 | std::string save_image_type_{}; 59 | 60 | // Internal state 61 | bool save_images_ = false; 62 | bool set_up_ = false; 63 | }; 64 | 65 | } // namespace srt3d 66 | 67 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_CAMERA_H_ 68 | -------------------------------------------------------------------------------- /source/include/srt3d/common.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_COMMON_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_COMMON_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace srt3d { 16 | 17 | // Commonly used types 18 | using Transform3fA = Eigen::Transform; 19 | 20 | // Commonly used constants 21 | constexpr float kPi = 3.1415926535898f; 22 | 23 | // Commonly used structs 24 | using Intrinsics = struct Intrinsics { 25 | float fu, fv; 26 | float ppu, ppv; 27 | int width, height; 28 | }; 29 | 30 | // Commonly used mathematic functions 31 | template 32 | inline int sgn(T value) { 33 | if (value < T(0)) 34 | return -1; 35 | else if (value > T(0)) 36 | return 1; 37 | else 38 | return 0; 39 | } 40 | 41 | template 42 | inline float sgnf(T value) { 43 | if (value < T(0)) 44 | return -1.0f; 45 | else if (value > T(0)) 46 | return 1.0f; 47 | else 48 | return 0.0f; 49 | } 50 | 51 | inline int pow_int(int x, int p) { 52 | if (p == 0) return 1; 53 | if (p == 1) return x; 54 | return pow_int(x, p - 1) * x; 55 | } 56 | 57 | inline Eigen::Matrix3f Vector2Skewsymmetric(const Eigen::Vector3f &vector) { 58 | Eigen::Matrix3f skew_symmetric; 59 | skew_symmetric << 0.0f, -vector(2), vector(1), vector(2), 0.0f, -vector(0), 60 | -vector(1), vector(0), 0.0f; 61 | return skew_symmetric; 62 | } 63 | 64 | // Commonly used functions to read and write value to file 65 | void ReadValueFromFile(std::ifstream &ifs, bool *value); 66 | void ReadValueFromFile(std::ifstream &ifs, int *value); 67 | void ReadValueFromFile(std::ifstream &ifs, float *value); 68 | void ReadValueFromFile(std::ifstream &ifs, std::string *value); 69 | void ReadValueFromFile(std::ifstream &ifs, Transform3fA *value); 70 | void ReadValueFromFile(std::ifstream &ifs, Intrinsics *value); 71 | void ReadValueFromFile(std::ifstream &ifs, std::filesystem::path *value); 72 | 73 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, bool value); 74 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, int value); 75 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, float value); 76 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 77 | const std::string &value); 78 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 79 | const Transform3fA &value); 80 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 81 | const Intrinsics &value); 82 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 83 | const std::filesystem::path &value); 84 | 85 | // Commonly used functions to plot points to image 86 | void DrawPointInImage(const Eigen::Vector3f &point_f_camera, 87 | const cv::Vec3b &color, const Intrinsics &intrinsics, 88 | cv::Mat *image); 89 | 90 | } // namespace srt3d 91 | 92 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_COMMON_H_ 93 | -------------------------------------------------------------------------------- /source/include/srt3d/model.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_MODEL_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_MODEL_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace srt3d { 27 | 28 | // Class that stores a sparse viewpoint model of a body that consists of views 29 | // with multiple contour points. It includes all functionality to generate, 30 | // save, and load the model 31 | class Model { 32 | private: 33 | // Some constants 34 | static constexpr int kVersionID = 2; 35 | static constexpr int kContourNormalApproxRadius = 3; 36 | static constexpr int kMinContourLength = 15; 37 | static constexpr int kImageSizeSafetyBoundary = 20; 38 | 39 | // Struct with operator that compares two Vector3f and checks if v1 < v2 40 | struct CompareSmallerVector3f { 41 | bool operator()(const Eigen::Vector3f &v1, 42 | const Eigen::Vector3f &v2) const { 43 | return v1[0] < v2[0] || (v1[0] == v2[0] && v1[1] < v2[1]) || 44 | (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] < v2[2]); 45 | } 46 | }; 47 | 48 | public: 49 | using PointData = struct PointData { 50 | Eigen::Vector3f center_f_body; 51 | Eigen::Vector3f normal_f_body; 52 | float foreground_distance = 0.0f; 53 | float background_distance = 0.0f; 54 | }; 55 | 56 | using TemplateView = struct TemplateView { 57 | std::vector data_points; 58 | Eigen::Vector3f orientation; // points from camera to body center 59 | }; 60 | 61 | // Constructors and setup methods 62 | Model(const std::string &name, std::shared_ptr body_ptr, 63 | const std::string &meta_file, 64 | float sphere_radius = 0.8, int n_divides = 4, int n_points = 200, 65 | bool use_random_seed = true, int image_size = 2000); 66 | bool SetUp(); 67 | 68 | // Setters 69 | void set_name(const std::string &name); 70 | void set_body_ptr(std::shared_ptr body_ptr); 71 | void set_meta_file(const std::string &meta_file); 72 | void set_sphere_radius(float sphere_radius); 73 | void set_n_divides(int n_divides); 74 | void set_n_points(int n_points); 75 | void set_use_random_seed(bool use_random_seed); 76 | void set_image_size(int image_size); 77 | 78 | // Main methods 79 | bool GetClosestTemplateView(const Transform3fA &body2camera_pose, 80 | const TemplateView **closest_template_view) const; 81 | 82 | // Getters 83 | const std::string &name() const; 84 | std::shared_ptr body_ptr() const; 85 | const std::string &meta_file() const; 86 | float sphere_radius() const; 87 | int n_divides() const; 88 | int n_points() const; 89 | bool use_random_seed() const; 90 | int image_size() const; 91 | bool set_up() const; 92 | 93 | private: 94 | // Helper methods for model set up 95 | bool GenerateModel(); 96 | bool LoadModel(); 97 | bool SaveModel() const; 98 | 99 | // Helper methods for point data 100 | bool GeneratePointData(const NormalRenderer &renderer, 101 | const Transform3fA &camera2body_pose, 102 | std::vector *data_points) const; 103 | bool GenerateValidContours(const cv::Mat &silhouette_image, 104 | std::vector> *contours, 105 | int *total_contour_length_in_pixel) const; 106 | static cv::Point2i SampleContourPointCoordinate( 107 | const std::vector> &contours, 108 | int total_contour_length_in_pixel, std::mt19937 &generator); 109 | static bool CalculateContourSegment( 110 | const std::vector> &contours, 111 | cv::Point2i ¢er, std::vector *contour_segment); 112 | static Eigen::Vector2f ApproximateNormalVector( 113 | const std::vector &contour_segment); 114 | void CalculateLineDistances( 115 | const cv::Mat &silhouette_image, 116 | const std::vector> &contours, 117 | const cv::Point2i ¢er, const Eigen::Vector2f &normal, 118 | float pixel_to_meter, float *foreground_distance, 119 | float *background_distance) const; 120 | static void FindClosestContourPoint( 121 | const std::vector> &contours, float u, float v, 122 | int *u_contour, int *v_contour); 123 | 124 | // Halper methods for view data 125 | bool SetUpRenderer( 126 | const std::shared_ptr &renderer_geometry_ptr, 127 | std::shared_ptr *renderer) const; 128 | void GenerateGeodesicPoses( 129 | std::vector *camera2body_poses) const; 130 | void GenerateGeodesicPoints( 131 | std::set *geodesic_points) const; 132 | static void SubdivideTriangle( 133 | const Eigen::Vector3f &v1, const Eigen::Vector3f &v2, 134 | const Eigen::Vector3f &v3, int n_divides, 135 | std::set *geodesic_points); 136 | 137 | // Model data 138 | std::vector template_views_; 139 | 140 | // Data 141 | std::string name_{}; 142 | std::shared_ptr body_ptr_ = nullptr; 143 | std::string meta_file_{}; 144 | float sphere_radius_{}; 145 | int n_divides_{}; 146 | int n_points_{}; 147 | bool use_random_seed_{}; 148 | int image_size_{}; 149 | bool set_up_ = false; 150 | }; 151 | 152 | } // namespace srt3d 153 | 154 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_MODEL_H_ 155 | -------------------------------------------------------------------------------- /source/include/srt3d/normal_renderer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_RENDERER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_RENDERER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace srt3d { 25 | 26 | // Renderer that is able to render both a depth image and an image where the 27 | // normal vector of the surface is encoded in the color of each pixel 28 | class NormalRenderer : public Renderer { 29 | public: 30 | // Constructors, destructors, and setup method 31 | NormalRenderer(const std::string &name, 32 | std::shared_ptr renderer_geometry_ptr, 33 | const Transform3fA &world2camera_pose, 34 | const Intrinsics &intrinsics, float z_min = 0.01f, 35 | float z_max = 5.0f, float depth_scale = 1000.0f); 36 | NormalRenderer(const std::string &name, 37 | std::shared_ptr renderer_geometry_ptr, 38 | std::shared_ptr camera_ptr, float z_min = 0.01f, 39 | float z_max = 5.0f, float depth_scale = 1000.0f); 40 | ~NormalRenderer(); 41 | bool SetUp() override; 42 | 43 | // Setters 44 | void set_depth_scale(float depth_scale); 45 | 46 | // Main method 47 | bool StartRendering() override; 48 | bool FetchNormalImage(); 49 | bool FetchDepthImage(); 50 | 51 | // Getters 52 | const cv::Mat &normal_image() const; 53 | const cv::Mat &depth_image() const; 54 | float depth_scale() const; 55 | 56 | // Getter that calculates a point vector based on a rendered depth image 57 | Eigen::Vector3f GetPointVector(const cv::Point2i &image_coordinate) const; 58 | 59 | private: 60 | // Helper methods 61 | void ClearImages(); 62 | void CalculateProjectionTerms(); 63 | void CreateBufferObjects(); 64 | void DeleteBufferObjects(); 65 | 66 | // Image data 67 | cv::Mat normal_image_; 68 | cv::Mat depth_image_; 69 | 70 | // Parameters 71 | float depth_scale_{}; // in units per meter 72 | 73 | // Shader code 74 | static std::string vertex_shader_code_; 75 | static std::string fragment_shader_code_; 76 | 77 | // OpenGL variables 78 | unsigned fbo_ = 0; 79 | unsigned rbo_normal_ = 0; 80 | unsigned rbo_depth_ = 0; 81 | unsigned shader_program_ = 0; 82 | 83 | // Internal variables 84 | float projection_term_a_ = 0; 85 | float projection_term_b_ = 0; 86 | 87 | // Internal state variables 88 | bool normal_image_fetched_ = false; 89 | bool depth_image_fetched_ = false; 90 | }; 91 | 92 | } // namespace srt3d 93 | 94 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_RENDERER_H_ 95 | -------------------------------------------------------------------------------- /source/include/srt3d/normal_viewer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_VIEWER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_VIEWER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace srt3d { 18 | 19 | // Viewer that renders all bodies into a normal image that is displayed on top 20 | // of a color camera image 21 | class NormalViewer : public Viewer { 22 | public: 23 | NormalViewer(const std::string &name, std::shared_ptr camera_ptr, 24 | std::shared_ptr renderer_geometry_ptr, 25 | float opacity = 0.5f); 26 | bool SetUp() override; 27 | 28 | // Setters 29 | void set_renderer_geometry_ptr( 30 | std::shared_ptr renderer_geometry_ptr); 31 | void set_opacity(float opacity); 32 | 33 | // Main methods 34 | bool UpdateViewer(int save_index) override; 35 | 36 | // Getters 37 | std::shared_ptr renderer_geometry_ptr() const override; 38 | float opacity() const; 39 | 40 | private: 41 | void CalculateAlphaBlend(const cv::Mat &camera_image, 42 | const cv::Mat &renderer_image, 43 | cv::Mat *viewer_image) const; 44 | 45 | std::shared_ptr renderer_geometry_ptr_ = nullptr; 46 | NormalRenderer renderer_; 47 | float opacity_ = 0.5f; 48 | }; 49 | 50 | } // namespace srt3d 51 | 52 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_NORMAL_VIEWER_H_ 53 | -------------------------------------------------------------------------------- /source/include/srt3d/occlusion_renderer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_OCCLUSION_RENDERER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_OCCLUSION_RENDERER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace srt3d { 25 | 26 | // Renderer that is able to render an occlusion mask, where all bodies are 27 | // enlarged by a certain dilation radius. The occlusion mask uses a binary 28 | // encoding. A body is considered occluded if the bit corresponding to a body's 29 | // occlusion_mask_id is zero and unoccluded if the bit is one. To improve 30 | // efficiency, a resolution can be set to decrease the amount of computation 31 | // that is required. 32 | class OcclusionRenderer : public Renderer { 33 | private: 34 | // Constants that define maximum radius in pixel for mask fragment shader 35 | // set to minimum to improve benchmarks 36 | static constexpr int kMaxEffectiveRadius = 1; 37 | static constexpr int kMaxTextureIterations = 38 | (kMaxEffectiveRadius * 2 + 1) * (kMaxEffectiveRadius * 2 + 1); 39 | 40 | public: 41 | // Constructors, destructor, and setup method 42 | OcclusionRenderer(const std::string &name, 43 | std::shared_ptr renderer_geometry_ptr, 44 | const Transform3fA &world2camera_pose, 45 | const Intrinsics &intrinsics, float z_min = 0.01f, 46 | float z_max = 5.0f, int mask_resolution = 4, 47 | float dilation_radius = 4.0f); 48 | OcclusionRenderer(const std::string &name, 49 | std::shared_ptr renderer_geometry_ptr, 50 | std::shared_ptr camera_ptr, float z_min = 0.01f, 51 | float z_max = 5.0f, int mask_resolution = 4, 52 | float dilation_radius = 4.0f); 53 | ~OcclusionRenderer(); 54 | bool SetUp() override; 55 | 56 | // Setters 57 | bool set_mask_resolution(int mask_resolution); 58 | bool set_dilation_radius(float dilation_radius); 59 | 60 | // Main method 61 | bool StartRendering() override; 62 | bool FetchOcclusionMask(); 63 | 64 | // Getters 65 | const cv::Mat &occlusion_mask() const; 66 | int mask_resolution() const; 67 | float dilation_radius() const; 68 | 69 | // Getter that considers the mask resolution to return a single mask value 70 | uchar GetValue(int v_unscaled, int u_unscaled) const; 71 | 72 | private: 73 | // Helper methods 74 | void ClearImages(); 75 | void CalculateMaskDimensions(); 76 | void CreateBufferObjects(); 77 | void DeleteBufferObjects(); 78 | void CreateVertexArrayAndBufferObjects(); 79 | void DeleteVertexArrayAndBufferObjects(); 80 | void GenerateTextureSteps(); 81 | void AssignUniformVariablesToShader(); 82 | 83 | // Mask data 84 | cv::Mat occlusion_mask_; 85 | 86 | // Parameters 87 | int mask_resolution_ = 4; 88 | float dilation_radius_ = 4.0f; 89 | 90 | // Shader code 91 | static std::string vertex_shader_code_body_id_; 92 | static std::string fragment_shader_code_body_id_; 93 | static std::string vertex_shader_code_mask_; 94 | static std::string fragment_shader_code_mask_; 95 | 96 | // OpenGL variables 97 | unsigned int fbo_body_id_ = 0; 98 | unsigned int fbo_mask_ = 0; 99 | unsigned int tex_body_id_ = 0; 100 | unsigned int tex_depth_ = 0; 101 | unsigned int rbo_mask_ = 0; 102 | unsigned int shader_program_body_id_ = 0; 103 | unsigned int shader_program_mask_ = 0; 104 | GLuint vao_texture_ = 0; 105 | GLuint vbo_texture_ = 0; 106 | 107 | // Internal variables 108 | int mask_width_ = 0; 109 | int mask_height_ = 0; 110 | int iterations_ = 0; 111 | std::array texture_steps_{}; 112 | 113 | // Internal state variables 114 | bool occlusion_mask_fetched_ = false; 115 | }; 116 | 117 | } // namespace srt3d 118 | 119 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_OCCLUSION_RENDERER_H_ 120 | -------------------------------------------------------------------------------- /source/include/srt3d/renderer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace srt3d { 22 | 23 | // Abstract class that defines a renderer as a single camera at a defined 24 | // location. Specifics with respect to the type of image rendered are 25 | // implemented in the derived class 26 | class Renderer { 27 | public: 28 | // Constructors and setup methods 29 | Renderer(const std::string &name, 30 | std::shared_ptr renderer_geometry_ptr, 31 | const Transform3fA &world2camera_pose, const Intrinsics &intrinsics, 32 | float z_min, float z_max); 33 | Renderer(const std::string &name, 34 | std::shared_ptr renderer_geometry_ptr, 35 | std::shared_ptr camera_ptr, float z_min, float z_max); 36 | virtual bool SetUp() = 0; 37 | 38 | // Setters 39 | void set_name(const std::string &name); 40 | void set_world2camera_pose(const Transform3fA &world2camera_pose); 41 | void set_camera2world_pose(const Transform3fA &camera2world_pose); 42 | void set_camera_ptr(std::shared_ptr camera_ptr); 43 | void set_renderer_geometry_ptr( 44 | std::shared_ptr renderer_geometry_ptr); 45 | void set_intrinsics(const Intrinsics &intrinsics); 46 | void set_z_min(float z_min); 47 | void set_z_max(float z_max); 48 | 49 | // Main methods 50 | virtual bool StartRendering() = 0; 51 | 52 | // Getters 53 | const std::string &name() const; 54 | const Transform3fA &world2camera_pose() const; 55 | const Transform3fA &camera2world_pose() const; 56 | std::shared_ptr camera_ptr() const; 57 | std::shared_ptr renderer_geometry_ptr() const; 58 | const Intrinsics &intrinsics() const; 59 | float z_min() const; 60 | float z_max() const; 61 | bool set_up() const; 62 | 63 | protected: 64 | // Helper Methods 65 | bool InitParametersFromCamera(); 66 | void CalculateProjectionMatrix(); 67 | bool CreateShaderProgram(const char *vertex_shader_code, 68 | const char *fragment_shader_code, 69 | unsigned *shader_program); 70 | static bool CheckCompileErrors(unsigned shader, const std::string &type); 71 | 72 | // Data 73 | std::string name_; 74 | std::shared_ptr renderer_geometry_ptr_ = nullptr; 75 | std::shared_ptr camera_ptr_ = nullptr; 76 | Transform3fA world2camera_pose_; 77 | Transform3fA camera2world_pose_; 78 | Intrinsics intrinsics_{}; 79 | float z_min_ = 0.01f; // min and max z-distance considered in clip space 80 | float z_max_ = 5.0f; 81 | Eigen::Matrix4f projection_matrix_; // projects 3d data into clip space 82 | 83 | // State variables 84 | std::mutex mutex_; 85 | bool image_rendered_ = false; 86 | bool initial_set_up_ = false; 87 | bool set_up_ = false; 88 | }; 89 | 90 | } // namespace srt3d 91 | 92 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_H_ 93 | -------------------------------------------------------------------------------- /source/include/srt3d/renderer_geometry.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_GEOMETRY_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_GEOMETRY_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace srt3d { 21 | 22 | // Class that holds rendering data for all assigned bodies as well as the glfw 23 | // context for the renderer 24 | class RendererGeometry { 25 | private: 26 | // Count the number of instances to manage the GLFW library 27 | static int n_instances_; 28 | 29 | public: 30 | // Data Structs 31 | using RenderDataBody = struct RenderDataBody { 32 | std::shared_ptr body_ptr = nullptr; 33 | GLuint vao = 0; 34 | GLuint vbo = 0; 35 | unsigned n_vertices = 0; 36 | }; 37 | 38 | // Constructor, destructor, and setup method 39 | // Both the destructor and setup method have to be called from 40 | // the main thread to comply with GLFW thread safety requirements 41 | RendererGeometry(const std::string &name); 42 | ~RendererGeometry(); // deletes glfw context 43 | bool SetUp(); // creates glfw context 44 | 45 | // Main methods 46 | bool AddBody(std::shared_ptr body_ptr, bool verbose = true); 47 | bool DeleteBody(const std::string &name, bool verbose = true); 48 | void ClearBodies(); 49 | 50 | // Handling of GLFW context 51 | void MakeContextCurrent(); 52 | void DetachContext(); 53 | 54 | // Getters 55 | const std::string &name() const; 56 | const std::vector &render_data_bodies() const; 57 | bool set_up() const; 58 | 59 | private: 60 | // Helper methods 61 | static bool LoadMeshIntoVertices(const Body &body, 62 | std::vector *vertices); 63 | static void CreateGLVertexObjects(const std::vector &vertices, 64 | RenderDataBody *render_data_body); 65 | static void DeleteGLVertexObjects(RenderDataBody *render_data_body); 66 | 67 | // Variables 68 | std::string name_{}; 69 | std::vector render_data_bodies_; 70 | GLFWwindow *window_ = nullptr; // only used to hold a glfw context 71 | std::mutex mutex_; 72 | bool initial_set_up_ = false; 73 | bool set_up_ = false; 74 | }; 75 | 76 | } // namespace srt3d 77 | 78 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_RENDERER_GEOMETRY_H_ 79 | -------------------------------------------------------------------------------- /source/include/srt3d/tracker.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_TRACKER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_TRACKER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace srt3d { 19 | 20 | // Class that holds multiple region modalities and viewers for visualization. It 21 | // coordinates all objects and referenced objects for continuous tracking. Also, 22 | // it defines how many correspondence iterations and pose update iterations are 23 | // executed and implements functionality that defines how long visualizations 24 | // are shown. 25 | class Tracker { 26 | public: 27 | // Constructor and setter methods 28 | Tracker(const std::string &name); 29 | void AddRegionModality(std::shared_ptr region_modality_ptr); 30 | // void AddViewer(std::shared_ptr viewer_ptr); 31 | void set_n_corr_iterations(int n_corr_iterations); 32 | void set_n_update_iterations(int n_update_iterations); 33 | // void set_visualization_time(int visualization_time); 34 | // void set_viewer_time(int viewer_time); 35 | 36 | // Main method 37 | bool SetUpTracker(); 38 | // bool StartTracker(bool start_tracking); 39 | 40 | // Methods for advanced use 41 | // bool ExecuteViewingCycle(int iteration); 42 | bool ExecuteTrackingCycle(int iteration); 43 | 44 | // Individual steps of tracking cycle for advanced use 45 | bool StartRegionModalities(); 46 | bool CalculateBeforeCameraUpdate(); 47 | bool UpdateCameras(); 48 | bool StartOcclusionRendering(); 49 | bool CalculateCorrespondences(int corr_iteration); 50 | // bool VisualizeCorrespondences(int save_idx); 51 | bool CalculatePoseUpdate(int corr_iteration, int update_iteration); 52 | // bool VisualizePoseUpdate(int save_idx); 53 | // bool VisualizeResults(int save_idx); 54 | // bool UpdateViewers(int save_idx); 55 | 56 | // Getters 57 | const std::string &name() const; 58 | std::vector> region_modality_ptrs() const; 59 | std::vector> viewer_ptrs() const; 60 | int n_corr_iterations() const; 61 | int n_update_iterations() const; 62 | // int visualization_time() const; 63 | // int viewer_time() const; 64 | bool set_up() const; 65 | 66 | // ==================== Additional ==================== 67 | bool TrackIter(const cv::Mat &occlusion_mask = cv::Mat()); 68 | std::vector EvaluateDistribution(); 69 | // cv::Mat RenderNormal(bool imshow = false); 70 | void ResetOcclusionMask(const cv::Mat &occlusion_mask = cv::Mat()); 71 | // ==================== Additional ==================== 72 | 73 | private: 74 | // Helper methods 75 | void AssambleDerivedObjectPtrs(); 76 | bool SetUpAllObjects(); 77 | 78 | // Objects 79 | std::vector> renderer_geometry_ptrs_; 80 | std::vector> camera_ptrs_; 81 | // std::vector> viewer_ptrs_; 82 | std::vector> model_ptrs_; 83 | std::vector> occlusion_renderer_ptrs_; 84 | std::vector> region_modality_ptrs_; 85 | 86 | // Parameters 87 | std::string name_{}; 88 | int n_corr_iterations_ = 7; 89 | int n_update_iterations_ = 2; 90 | // int visualization_time_ = 1; 91 | // int viewer_time_ = 1; 92 | 93 | // State variables 94 | // bool start_tracking_ = false; 95 | // bool tracking_started_ = false; 96 | bool set_up_ = false; 97 | bool init_ = false; 98 | }; 99 | 100 | template 101 | void AddPtrIfNameNotExists(T &&ptr, std::vector *ptrs) { 102 | if (std::none_of(begin(*ptrs), end(*ptrs), 103 | [&ptr](const T &p) { return p->name() == ptr->name(); })) { 104 | ptrs->push_back(std::move(ptr)); 105 | } 106 | } 107 | 108 | template 109 | bool SetUpObjectPtrs(std::vector *ptrs) { 110 | for (T &ptr : *ptrs) { 111 | if (!ptr->SetUp()) { 112 | std::cout << "Error setting up " << ptr->name() << std::endl; 113 | return false; 114 | } 115 | } 116 | return true; 117 | } 118 | 119 | } // namespace srt3d 120 | 121 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_TRACKER_H_ 122 | -------------------------------------------------------------------------------- /source/include/srt3d/viewer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #ifndef OBJECT_TRACKING_INCLUDE_SRT3D_VIEWER_H_ 5 | #define OBJECT_TRACKING_INCLUDE_SRT3D_VIEWER_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace srt3d { 16 | 17 | // Abstract class that defines a viewer and functionality to view and save the 18 | // current tracking state 19 | class Viewer { 20 | public: 21 | // Constructor and setup method 22 | Viewer(const std::string &name, std::shared_ptr camera_ptr); 23 | virtual bool SetUp() = 0; 24 | 25 | // Setters 26 | void set_name(const std::string &name); 27 | void set_camera_ptr(std::shared_ptr camera_ptr); 28 | void set_display_images(bool dispaly_images); 29 | void StartSavingImages(const std::filesystem::path &save_directory, 30 | const std::string &save_image_type = "png"); 31 | void StopSavingImages(); 32 | 33 | // Main methods 34 | virtual bool UpdateViewer(int save_index) = 0; 35 | void DisplayImage(); 36 | 37 | // Getters 38 | const cv::Mat &viewer_image() const; 39 | const std::string &name() const; 40 | std::shared_ptr camera_ptr() const; 41 | virtual std::shared_ptr renderer_geometry_ptr() const; 42 | bool display_images() const; 43 | bool save_images() const; 44 | bool set_up() const; 45 | 46 | protected: 47 | // Helper methods 48 | void DisplayAndSaveImage(int save_index, const cv::Mat &image); 49 | 50 | // Variables 51 | std::string name_{}; 52 | std::shared_ptr camera_ptr_ = nullptr; 53 | std::filesystem::path save_directory_{}; 54 | std::string save_image_type_{}; 55 | bool display_images_ = true; 56 | bool save_images_ = false; 57 | bool set_up_ = false; 58 | cv::Mat viewer_image_{}; 59 | }; 60 | 61 | } // namespace srt3d 62 | 63 | #endif // OBJECT_TRACKING_INCLUDE_SRT3D_VIEWER_H_ 64 | -------------------------------------------------------------------------------- /source/pysrt3d/pysrt3d.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "virtual_camera.hpp" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace py = pybind11; 27 | 28 | // convert numpy array to cv::Mat 29 | cv::Mat convert_numpy_cvmat(const py::array_t& input, bool gray_scale = false); 30 | // calculate pose uv 31 | cv::Point2i calculate_pose_uv(const Eigen::Matrix4f& pose, const Eigen::Matrix3f& K); 32 | 33 | 34 | class RegionModel{ 35 | public: 36 | // constructor 37 | RegionModel(const std::string& name, 38 | const std::string& geometry_path, 39 | const std::string& meta_path = "", 40 | const float unit_in_meter = 1.0, 41 | const float shpere_radius = 0.8, 42 | const bool from_opengl = false, 43 | const Eigen::Matrix4f& geometry2body = Eigen::Matrix4f::Identity(), 44 | const float threshold_on_init = 0.8, 45 | const float threshold_on_track = 0.5, 46 | const float kl_threshold = 1.0, 47 | const bool debug_visualize = false 48 | ); 49 | // setup tracker 50 | void Setup(); 51 | 52 | // variables 53 | const std::string name_; 54 | std::shared_ptr body_ptr_; 55 | std::shared_ptr model_ptr_; 56 | std::shared_ptr region_modality_ptr_ = nullptr; 57 | float threshold_on_init_; 58 | float threshold_on_track_; 59 | float kl_threshold_ = 1.0; 60 | bool debug_visualize_; 61 | 62 | // states 63 | float conf_ = 0.0; 64 | Eigen::Matrix4f last_pose_ = Eigen::Matrix4f::Identity(); 65 | int state_ = 1; 66 | cv::Point2i uv_; 67 | 68 | // methods 69 | // void set_target_rotation(const Eigen::Matrix3f& rot); 70 | void set_kl_threshold(const float kl_threshold); 71 | void reset_pose(const Eigen::Matrix4f& pose = Eigen::Matrix4f::Identity()); 72 | const Eigen::Matrix4f pose(); 73 | const Eigen::Matrix4f pose_gl(); 74 | bool validate(); 75 | float valid_percentage(); 76 | 77 | }; // class Model 78 | 79 | 80 | class RegionTracker{ 81 | public: 82 | RegionTracker(const int imwidth, const int imheight, 83 | const Eigen::Matrix3f& K = Eigen::Matrix3f::Zero(), 84 | const float fx = 0.0, const float fy = 0.0, 85 | const float cx = 0.0, const float cy = 0.0, 86 | const int corr_update_iter = 7, const int pose_update_iter = 2); 87 | // add region model 88 | void add_model(const std::shared_ptr& region_model); 89 | // track 90 | void track(const py::array_t& image, std::optional> mask); 91 | // setup 92 | void setup(); 93 | // delete 94 | void terminate(); 95 | 96 | int imwidth_; 97 | int imheight_; 98 | int focal_; 99 | Eigen::Matrix3f K_; 100 | 101 | std::vector> models_; 102 | std::shared_ptr tracker_ptr_; 103 | std::shared_ptr camera_ptr_; 104 | 105 | }; // class tracker 106 | 107 | 108 | class RegionRenderer{ 109 | public: 110 | RegionRenderer(const std::shared_ptr& region_tracker_ptr); 111 | py::array_t render(); 112 | 113 | std::shared_ptr region_tracker_; 114 | std::shared_ptr renderer_geometry_ptr_; 115 | std::shared_ptr viewer_ptr_; 116 | std::shared_ptr camera_ptr_; 117 | }; // class renderer 118 | 119 | 120 | -------------------------------------------------------------------------------- /source/pysrt3d/virtual_camera.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace srt3d { 9 | 10 | class VirtualCamera : public Camera{ 11 | public: 12 | VirtualCamera(std::string name) : Camera(name) {} 13 | ~VirtualCamera() {} 14 | 15 | void set_intrinsics(const srt3d::Intrinsics& intrinsics) { 16 | intrinsics_ = intrinsics; 17 | } 18 | 19 | bool SetUp() override { 20 | set_up_ = true; 21 | return true; 22 | } 23 | 24 | void PushImage(cv::Mat& image) { 25 | if(image.cols == 0 || image.rows == 0 || image.empty()) { 26 | std::cerr << "[warn] got empty image" << std::endl; 27 | return; 28 | } 29 | image_list_.push(image.clone()); 30 | } 31 | 32 | void set_realtime(bool flag) { 33 | force_realtime_ = flag; 34 | } 35 | 36 | bool UpdateImage() override { 37 | if (image_list_.empty()) { 38 | return !image_.empty(); 39 | } 40 | 41 | image_ = image_list_.front(); 42 | image_list_.pop(); 43 | // drop frames 44 | if(force_realtime_) { 45 | while(image_list_.size() > 0) { 46 | image_ = image_list_.front(); 47 | image_list_.pop(); 48 | } 49 | } 50 | 51 | return true; 52 | } 53 | 54 | protected: 55 | std::queue image_list_; 56 | bool force_realtime_ = false; 57 | 58 | }; // class Virtual Camera 59 | 60 | 61 | } // namespace srt3d -------------------------------------------------------------------------------- /source/src/body.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | // #define TINYOBJLOADER_IMPLEMENTATION 7 | #include 8 | 9 | namespace srt3d { 10 | 11 | Body::Body(const std::string &name, const std::filesystem::path &geometry_path, 12 | float geometry_unit_in_meter, bool geometry_counterclockwise, 13 | bool geometry_enable_culling, const Transform3fA &geometry2body_pose) 14 | : name_{name}, 15 | geometry_path_{geometry_path}, 16 | geometry_unit_in_meter_{geometry_unit_in_meter}, 17 | geometry_counterclockwise_{geometry_counterclockwise}, 18 | geometry_enable_culling_{geometry_enable_culling}, 19 | geometry2body_pose_{geometry2body_pose} 20 | { 21 | geometry2world_pose_ = geometry2body_pose; 22 | world2geometry_pose_ = geometry2world_pose_.inverse(); 23 | calculate_maximum_body_diameter(); 24 | } 25 | 26 | void Body::set_name(const std::string &name) { name_ = name; } 27 | 28 | void Body::set_geometry_path(const std::filesystem::path &geometry_path) { 29 | geometry_path_ = geometry_path; 30 | } 31 | 32 | void Body::set_geometry_unit_in_meter(float geometry_unit_in_meter) { 33 | geometry_unit_in_meter_ = geometry_unit_in_meter; 34 | } 35 | 36 | void Body::set_geometry_counterclockwise(bool geometry_counterclockwise) { 37 | geometry_counterclockwise_ = geometry_counterclockwise; 38 | } 39 | 40 | void Body::set_geometry_enable_culling(bool geometry_enable_culling) { 41 | geometry_enable_culling_ = geometry_enable_culling; 42 | } 43 | 44 | // void Body::set_maximum_body_diameter(float maximum_body_diameter) { 45 | // maximum_body_diameter_ = maximum_body_diameter; 46 | // } 47 | 48 | void Body::set_geometry2body_pose(const Transform3fA &geometry2body_pose) { 49 | geometry2body_pose_ = geometry2body_pose; 50 | geometry2world_pose_ = body2world_pose_ * geometry2body_pose_; 51 | world2geometry_pose_ = geometry2world_pose_.inverse(); 52 | } 53 | 54 | // bool Body::set_occlusion_id(int occlusion_id) { 55 | // if (occlusion_id > 7) { 56 | // std::cout << "Invalid value for occlusion id. Has to be <= 7." << std::endl; 57 | // return false; 58 | // } 59 | // occlusion_id_ = occlusion_id; 60 | // return true; 61 | // } 62 | 63 | void Body::set_body2world_pose(const Transform3fA &body2world_pose) { 64 | body2world_pose_ = body2world_pose; 65 | world2body_pose_ = body2world_pose_.inverse(); 66 | geometry2world_pose_ = body2world_pose_ * geometry2body_pose_; 67 | world2geometry_pose_ = geometry2world_pose_.inverse(); 68 | } 69 | 70 | void Body::set_world2body_pose(const Transform3fA &world2body_pose) { 71 | world2body_pose_ = world2body_pose; 72 | body2world_pose_ = world2body_pose_.inverse(); 73 | geometry2world_pose_ = body2world_pose_ * geometry2body_pose_; 74 | world2geometry_pose_ = geometry2world_pose_.inverse(); 75 | } 76 | 77 | const std::string &Body::name() const { return name_; } 78 | 79 | int Body::occlusion_id() const { return occlusion_id_; } 80 | 81 | const std::filesystem::path &Body::geometry_path() const { 82 | return geometry_path_; 83 | } 84 | 85 | float Body::geometry_unit_in_meter() const { return geometry_unit_in_meter_; } 86 | 87 | bool Body::geometry_counterclockwise() const { 88 | return geometry_counterclockwise_; 89 | } 90 | 91 | bool Body::geometry_enable_culling() const { return geometry_enable_culling_; } 92 | 93 | float Body::maximum_body_diameter() const { return maximum_body_diameter_; } 94 | 95 | const Transform3fA &Body::geometry2body_pose() const { 96 | return geometry2body_pose_; 97 | } 98 | 99 | const Transform3fA &Body::body2world_pose() const { return body2world_pose_; } 100 | 101 | const Transform3fA &Body::world2body_pose() const { return world2body_pose_; } 102 | 103 | const Transform3fA &Body::geometry2world_pose() const { 104 | return geometry2world_pose_; 105 | } 106 | 107 | const Transform3fA &Body::world2geometry_pose() const { 108 | return world2geometry_pose_; 109 | } 110 | 111 | void Body::calculate_maximum_body_diameter() { 112 | // load mesh data 113 | tinyobj::attrib_t attributes; 114 | std::vector vertices; 115 | std::vector shapes; 116 | std::vector materials; 117 | std::string warning; 118 | std::string error; 119 | 120 | if (!tinyobj::LoadObj(&attributes, &shapes, &materials, &warning, &error, 121 | geometry_path_.string().c_str(), nullptr, true, 122 | false)) { 123 | std::cerr << "TinyObjLoader failed to load data from " << geometry_path_ 124 | << std::endl; 125 | return; 126 | } 127 | if (!error.empty()) std::cerr << error << std::endl; 128 | 129 | vertices.resize(attributes.vertices.size() / 3); 130 | memcpy(vertices.data(), attributes.vertices.data(), 131 | sizeof(float) * attributes.vertices.size()); 132 | if (geometry_unit_in_meter_ != 1.0f) { 133 | for (auto &vertex : vertices) { 134 | vertex *= geometry_unit_in_meter_; 135 | } 136 | } 137 | 138 | // calculate maximum body diameter 139 | float max_radius = 0.0f; 140 | for (const auto &vertex : vertices) { 141 | max_radius = std::max(max_radius, (geometry2body_pose_ * vertex).norm()); 142 | } 143 | maximum_body_diameter_ = 2.2f * max_radius; 144 | // std::cout << "Maximum body diameter: " << maximum_body_diameter_ << std::endl; 145 | 146 | } 147 | 148 | } // namespace srt3d 149 | -------------------------------------------------------------------------------- /source/src/camera.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | namespace srt3d { 7 | 8 | Camera::Camera(const std::string &name) : name_{name} {} 9 | 10 | void Camera::set_name(const std::string &name) { name_ = name; } 11 | 12 | void Camera::set_camera2world_pose(const Transform3fA &camera2world_pose) { 13 | camera2world_pose_ = camera2world_pose; 14 | world2camera_pose_ = camera2world_pose_.inverse(); 15 | } 16 | 17 | void Camera::set_world2camera_pose(const Transform3fA &world2camera_pose) { 18 | world2camera_pose_ = world2camera_pose; 19 | camera2world_pose_ = world2camera_pose_.inverse(); 20 | } 21 | 22 | void Camera::StartSavingImages(const std::filesystem::path &save_directory, 23 | int save_index, 24 | const std::string &save_image_type) { 25 | save_images_ = true; 26 | save_directory_ = save_directory; 27 | save_index_ = save_index; 28 | save_image_type_ = save_image_type; 29 | set_up_ = false; 30 | } 31 | 32 | void Camera::StopSavingImages() { save_images_ = false; } 33 | 34 | const cv::Mat &Camera::image() const { return image_; } 35 | 36 | const std::string &Camera::name() const { return name_; } 37 | 38 | const Intrinsics &Camera::intrinsics() const { return intrinsics_; } 39 | 40 | const Transform3fA &Camera::camera2world_pose() const { 41 | return camera2world_pose_; 42 | } 43 | 44 | const Transform3fA &Camera::world2camera_pose() const { 45 | return world2camera_pose_; 46 | } 47 | 48 | bool Camera::save_images() const { return save_images_; } 49 | 50 | bool Camera::set_up() const { return set_up_; } 51 | 52 | void Camera::SaveMetaDataIfDesired() const { 53 | if (save_images_) { 54 | std::filesystem::path path{save_directory_ / (name_ + "_meta.txt")}; 55 | std::ofstream ofs{path}; 56 | WriteValueToFile(ofs, "image_name_pre_", (name_ + "_image_")); 57 | WriteValueToFile(ofs, "load_index_", save_index_); 58 | WriteValueToFile(ofs, "n_leading_zeros_", 0); 59 | WriteValueToFile(ofs, "image_name_post", std::string{""}); 60 | WriteValueToFile(ofs, "load_image_type_", save_image_type_); 61 | WriteValueToFile(ofs, "intrinsics_", intrinsics_); 62 | WriteValueToFile(ofs, "camera2world_pose_", camera2world_pose_); 63 | ofs.flush(); 64 | ofs.close(); 65 | } 66 | } 67 | 68 | void Camera::SaveImageIfDesired() { 69 | if (save_images_) { 70 | std::filesystem::path path{save_directory_ / (name_ + "_image_" + 71 | std::to_string(save_index_) + 72 | "." + save_image_type_)}; 73 | cv::imwrite(path.string(), image_); 74 | save_index_++; 75 | } 76 | } 77 | 78 | } // namespace srt3d 79 | -------------------------------------------------------------------------------- /source/src/common.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | namespace srt3d { 7 | 8 | void ReadValueFromFile(std::ifstream &ifs, bool *value) { 9 | std::string parsed; 10 | std::getline(ifs, parsed); 11 | std::getline(ifs, parsed, '\t'); 12 | *value = stoi(parsed); 13 | std::getline(ifs, parsed); 14 | } 15 | 16 | void ReadValueFromFile(std::ifstream &ifs, int *value) { 17 | std::string parsed; 18 | std::getline(ifs, parsed); 19 | std::getline(ifs, parsed, '\t'); 20 | *value = stoi(parsed); 21 | std::getline(ifs, parsed); 22 | } 23 | 24 | void ReadValueFromFile(std::ifstream &ifs, float *value) { 25 | std::string parsed; 26 | std::getline(ifs, parsed); 27 | std::getline(ifs, parsed, '\t'); 28 | *value = stof(parsed); 29 | std::getline(ifs, parsed); 30 | } 31 | 32 | void ReadValueFromFile(std::ifstream &ifs, std::string *value) { 33 | std::string parsed; 34 | std::getline(ifs, parsed); 35 | std::getline(ifs, *value, '\t'); 36 | std::getline(ifs, parsed); 37 | } 38 | 39 | void ReadValueFromFile(std::ifstream &ifs, Transform3fA *value) { 40 | std::string parsed; 41 | std::getline(ifs, parsed); 42 | Eigen::Matrix4f mat; 43 | for (int i = 0; i < 4; ++i) { 44 | for (int j = 0; j < 4; ++j) { 45 | std::getline(ifs, parsed, '\t'); 46 | mat(i, j) = stof(parsed); 47 | } 48 | std::getline(ifs, parsed); 49 | } 50 | *value = Transform3fA(mat); 51 | } 52 | 53 | void ReadValueFromFile(std::ifstream &ifs, Intrinsics *value) { 54 | std::string parsed; 55 | std::getline(ifs, parsed); 56 | std::getline(ifs, parsed); 57 | std::getline(ifs, parsed, '\t'); 58 | value->fu = stof(parsed); 59 | std::getline(ifs, parsed, '\t'); 60 | value->fv = stof(parsed); 61 | std::getline(ifs, parsed, '\t'); 62 | value->ppu = stof(parsed); 63 | std::getline(ifs, parsed, '\t'); 64 | value->ppv = stof(parsed); 65 | std::getline(ifs, parsed, '\t'); 66 | value->width = stoi(parsed); 67 | std::getline(ifs, parsed, '\t'); 68 | value->height = stoi(parsed); 69 | std::getline(ifs, parsed); 70 | } 71 | 72 | void ReadValueFromFile(std::ifstream &ifs, std::filesystem::path *value) { 73 | std::string parsed; 74 | std::getline(ifs, parsed); 75 | std::getline(ifs, parsed, '\t'); 76 | value->assign(parsed); 77 | std::getline(ifs, parsed); 78 | } 79 | 80 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, bool value) { 81 | ofs << name << std::endl; 82 | ofs << value << "\t" << std::endl; 83 | } 84 | 85 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, int value) { 86 | ofs << name << std::endl; 87 | ofs << value << "\t" << std::endl; 88 | } 89 | 90 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 91 | float value) { 92 | ofs << name << std::endl; 93 | ofs << value << "\t" << std::endl; 94 | } 95 | 96 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 97 | const std::string &value) { 98 | ofs << name << std::endl; 99 | ofs << value << "\t" << std::endl; 100 | } 101 | 102 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 103 | const Transform3fA &value) { 104 | ofs << name << std::endl; 105 | for (int i = 0; i < 4; ++i) { 106 | for (int j = 0; j < 4; ++j) { 107 | ofs << value.matrix()(i, j) << "\t"; 108 | } 109 | ofs << std::endl; 110 | } 111 | } 112 | 113 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 114 | const Intrinsics &value) { 115 | ofs << name << std::endl; 116 | ofs << "f_x, \t f_y, \t pp_x, \t pp_y, \t width, \t height" << std::endl; 117 | ofs << value.fu << "\t"; 118 | ofs << value.fv << "\t"; 119 | ofs << value.ppu << "\t"; 120 | ofs << value.ppv << "\t"; 121 | ofs << value.width << "\t"; 122 | ofs << value.height << "\t"; 123 | ofs << std::endl; 124 | } 125 | 126 | void WriteValueToFile(std::ofstream &ofs, const std::string &name, 127 | const std::filesystem::path &value) { 128 | ofs << name << std::endl; 129 | ofs << value.string() << "\t" << std::endl; 130 | } 131 | 132 | void DrawPointInImage(const Eigen::Vector3f &point_f_camera, 133 | const cv::Vec3b &color, const Intrinsics &intrinsics, 134 | cv::Mat *image) { 135 | int u = int(point_f_camera(0) * intrinsics.fu / point_f_camera(2) + 136 | intrinsics.ppu + 0.5); 137 | int v = int(point_f_camera(1) * intrinsics.fv / point_f_camera(2) + 138 | intrinsics.ppv + 0.5); 139 | if (u >= 1 && v >= 1 && u <= image->cols - 2 && v <= image->rows - 2) { 140 | image->at(v, u) = color; 141 | image->at(v - 1, u) = color; 142 | image->at(v + 1, u) = color; 143 | image->at(v, u - 1) = color; 144 | image->at(v, u + 1) = color; 145 | } 146 | } 147 | 148 | } // namespace srt3d 149 | -------------------------------------------------------------------------------- /source/src/normal_viewer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | namespace srt3d { 7 | 8 | NormalViewer::NormalViewer( 9 | const std::string &name, std::shared_ptr camera_ptr, 10 | std::shared_ptr renderer_geometry_ptr, float opacity) 11 | : Viewer{name, camera_ptr}, 12 | renderer_geometry_ptr_{renderer_geometry_ptr}, 13 | opacity_{opacity}, 14 | renderer_{"renderer", std::move(renderer_geometry_ptr), 15 | std::move(camera_ptr)} {} 16 | 17 | bool NormalViewer::SetUp() { 18 | set_up_ = false; 19 | 20 | // Check if all required objects are set up 21 | if (!camera_ptr_->set_up()) { 22 | std::cerr << "Camera " << camera_ptr_->name() << " was not set up" 23 | << std::endl; 24 | return false; 25 | } 26 | if (!renderer_geometry_ptr_->set_up()) { 27 | std::cerr << "Renderer geometry " << renderer_geometry_ptr_->name() 28 | << " was not set up" << std::endl; 29 | return false; 30 | } 31 | 32 | if (!renderer_.SetUp()) return false; 33 | set_up_ = true; 34 | return true; 35 | } 36 | 37 | void NormalViewer::set_renderer_geometry_ptr( 38 | std::shared_ptr renderer_geometry_ptr) { 39 | renderer_geometry_ptr_ = std::move(renderer_geometry_ptr); 40 | set_up_ = false; 41 | } 42 | 43 | void NormalViewer::set_opacity(float opacity) { opacity_ = opacity; } 44 | 45 | bool NormalViewer::UpdateViewer(int save_index) { 46 | if (!set_up_) { 47 | std::cerr << "Set up viewer " << name_ << " first" << std::endl; 48 | return false; 49 | } 50 | 51 | // Calculate viewer image 52 | cv::Mat viewer_image{camera_ptr_->image().size(), CV_8UC3}; 53 | renderer_.StartRendering(); 54 | renderer_.FetchNormalImage(); 55 | CalculateAlphaBlend(camera_ptr_->image(), renderer_.normal_image(), 56 | &viewer_image); 57 | viewer_image_ = viewer_image; 58 | 59 | // Display and save images 60 | // DisplayAndSaveImage(save_index, viewer_image); 61 | return true; 62 | } 63 | 64 | std::shared_ptr NormalViewer::renderer_geometry_ptr() const { 65 | return renderer_geometry_ptr_; 66 | } 67 | 68 | float NormalViewer::opacity() const { return opacity_; } 69 | 70 | void NormalViewer::CalculateAlphaBlend(const cv::Mat &camera_image, 71 | const cv::Mat &renderer_image, 72 | cv::Mat *viewer_image) const { 73 | // Declare variables 74 | int v, u; 75 | const cv::Vec3b *ptr_camera_image; 76 | const cv::Vec4b *ptr_renderer_image; 77 | cv::Vec3b *ptr_viewer_image; 78 | const uchar *val_camera_image; 79 | const uchar *val_renderer_image; 80 | uchar *val_viewer_image; 81 | float alpha, alpha_inv; 82 | float alpha_scale = opacity_ / 255.0f; 83 | 84 | // Iterate over all pixels 85 | for (v = 0; v < camera_image.rows; ++v) { 86 | ptr_camera_image = camera_image.ptr(v); 87 | ptr_renderer_image = renderer_image.ptr(v); 88 | ptr_viewer_image = viewer_image->ptr(v); 89 | for (u = 0; u < camera_image.cols; ++u) { 90 | val_camera_image = ptr_camera_image[u].val; 91 | val_renderer_image = ptr_renderer_image[u].val; 92 | val_viewer_image = ptr_viewer_image[u].val; 93 | 94 | // Blend images 95 | alpha = float(val_renderer_image[3]) * alpha_scale; 96 | alpha_inv = 1.0f - alpha; 97 | val_viewer_image[0] = 98 | char(val_camera_image[0] * alpha_inv + val_renderer_image[0] * alpha); 99 | val_viewer_image[1] = 100 | char(val_camera_image[1] * alpha_inv + val_renderer_image[1] * alpha); 101 | val_viewer_image[2] = 102 | char(val_camera_image[2] * alpha_inv + val_renderer_image[2] * alpha); 103 | } 104 | } 105 | } 106 | 107 | } // namespace srt3d 108 | -------------------------------------------------------------------------------- /source/src/renderer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | namespace srt3d { 7 | 8 | Renderer::Renderer(const std::string &name, 9 | std::shared_ptr renderer_geometry_ptr, 10 | const Transform3fA &world2camera_pose, 11 | const Intrinsics &intrinsics, float z_min, float z_max) 12 | : name_{name}, 13 | renderer_geometry_ptr_{std::move(renderer_geometry_ptr)}, 14 | intrinsics_{intrinsics}, 15 | z_min_{z_min}, 16 | z_max_{z_max} { 17 | world2camera_pose_ = world2camera_pose; 18 | camera2world_pose_ = world2camera_pose.inverse(); 19 | } 20 | 21 | Renderer::Renderer(const std::string &name, 22 | std::shared_ptr renderer_geometry_ptr, 23 | std::shared_ptr camera_ptr, float z_min, float z_max) 24 | : name_{name}, 25 | renderer_geometry_ptr_{std::move(renderer_geometry_ptr)}, 26 | camera_ptr_{std::move(camera_ptr)}, 27 | z_min_{z_min}, 28 | z_max_{z_max} {} 29 | 30 | void Renderer::set_name(const std::string &name) { 31 | const std::lock_guard lock{mutex_}; 32 | name_ = name; 33 | } 34 | 35 | void Renderer::set_world2camera_pose(const Transform3fA &world2camera_pose) { 36 | const std::lock_guard lock{mutex_}; 37 | world2camera_pose_ = world2camera_pose; 38 | camera2world_pose_ = world2camera_pose.inverse(); 39 | } 40 | 41 | void Renderer::set_camera2world_pose(const Transform3fA &camera2world_pose) { 42 | const std::lock_guard lock{mutex_}; 43 | camera2world_pose_ = camera2world_pose; 44 | world2camera_pose_ = camera2world_pose.inverse(); 45 | } 46 | 47 | void Renderer::set_camera_ptr(std::shared_ptr camera_ptr) { 48 | const std::lock_guard lock{mutex_}; 49 | camera_ptr_ = std::move(camera_ptr); 50 | set_up_ = false; 51 | } 52 | 53 | void Renderer::set_renderer_geometry_ptr( 54 | std::shared_ptr renderer_geometry_ptr) { 55 | const std::lock_guard lock{mutex_}; 56 | renderer_geometry_ptr_ = std::move(renderer_geometry_ptr); 57 | set_up_ = false; 58 | } 59 | 60 | void Renderer::set_intrinsics(const Intrinsics &intrinsics) { 61 | const std::lock_guard lock{mutex_}; 62 | intrinsics_ = intrinsics; 63 | set_up_ = false; 64 | } 65 | 66 | void Renderer::set_z_min(float z_min) { 67 | const std::lock_guard lock{mutex_}; 68 | z_min_ = z_min; 69 | set_up_ = false; 70 | } 71 | 72 | void Renderer::set_z_max(float z_max) { 73 | const std::lock_guard lock{mutex_}; 74 | z_max_ = z_max; 75 | set_up_ = false; 76 | } 77 | 78 | const std::string &Renderer::name() const { return name_; } 79 | 80 | std::shared_ptr Renderer::camera_ptr() const { return camera_ptr_; } 81 | 82 | std::shared_ptr Renderer::renderer_geometry_ptr() const { 83 | return renderer_geometry_ptr_; 84 | } 85 | 86 | const Transform3fA &Renderer::world2camera_pose() const { 87 | return world2camera_pose_; 88 | } 89 | 90 | const Transform3fA &Renderer::camera2world_pose() const { 91 | return camera2world_pose_; 92 | } 93 | 94 | const Intrinsics &Renderer::intrinsics() const { return intrinsics_; } 95 | 96 | float Renderer::z_min() const { return z_min_; } 97 | 98 | float Renderer::z_max() const { return z_max_; } 99 | 100 | bool Renderer::set_up() const { return set_up_; }; 101 | 102 | bool Renderer::InitParametersFromCamera() { 103 | if (!camera_ptr_->set_up()) { 104 | std::cerr << "Camera " << camera_ptr_->name() << " was not set up" 105 | << std::endl; 106 | return false; 107 | } 108 | intrinsics_ = camera_ptr_->intrinsics(); 109 | world2camera_pose_ = camera_ptr_->world2camera_pose(); 110 | camera2world_pose_ = camera_ptr_->camera2world_pose(); 111 | return true; 112 | } 113 | 114 | void Renderer::CalculateProjectionMatrix() { 115 | projection_matrix_ << 2.0f * intrinsics_.fu / float(intrinsics_.width), 0.0f, 116 | 2.0f * (intrinsics_.ppu + 0.5f) / float(intrinsics_.width) - 1.0f, 0.0f, 117 | 0.0f, 2.0f * intrinsics_.fv / float(intrinsics_.height), 118 | 2.0f * (intrinsics_.ppv + 0.5f) / float(intrinsics_.height) - 1.0f, 0.0f, 119 | 0.0f, 0.0f, (z_max_ + z_min_) / (z_max_ - z_min_), 120 | -2.0f * z_max_ * z_min_ / (z_max_ - z_min_), 0.0f, 0.0f, 1.0f, 0.0f; 121 | } 122 | 123 | bool Renderer::CreateShaderProgram(const char *vertex_shader_code, 124 | const char *fragment_shader_code, 125 | unsigned *shader_program) { 126 | renderer_geometry_ptr_->MakeContextCurrent(); 127 | 128 | // Create shader 129 | unsigned vertex_shader = glCreateShader(GL_VERTEX_SHADER); 130 | glShaderSource(vertex_shader, 1, &vertex_shader_code, nullptr); 131 | glCompileShader(vertex_shader); 132 | if (!CheckCompileErrors(vertex_shader, "VERTEX")) return false; 133 | 134 | unsigned fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 135 | glShaderSource(fragment_shader, 1, &fragment_shader_code, nullptr); 136 | glCompileShader(fragment_shader); 137 | if (!CheckCompileErrors(fragment_shader, "FRAGMENT")) return false; 138 | 139 | // Create shader programs 140 | *shader_program = glCreateProgram(); 141 | glAttachShader(*shader_program, vertex_shader); 142 | glAttachShader(*shader_program, fragment_shader); 143 | glLinkProgram(*shader_program); 144 | if (!CheckCompileErrors(*shader_program, "PROGRAM")) return false; 145 | 146 | glDeleteShader(vertex_shader); 147 | glDeleteShader(fragment_shader); 148 | renderer_geometry_ptr_->DetachContext(); 149 | return true; 150 | } 151 | 152 | bool Renderer::CheckCompileErrors(unsigned shader, const std::string &type) { 153 | int success; 154 | char info_log[1024]; 155 | if (type != "PROGRAM") { 156 | glGetShaderiv(shader, GL_COMPILE_STATUS, &success); 157 | if (!success) { 158 | glGetShaderInfoLog(shader, 1024, nullptr, info_log); 159 | std::cerr << "Shader compilation error of type: " << type << std::endl 160 | << info_log << std::endl; 161 | return false; 162 | } 163 | } else { 164 | glGetProgramiv(shader, GL_LINK_STATUS, &success); 165 | if (!success) { 166 | glGetProgramInfoLog(shader, 1024, nullptr, info_log); 167 | std::cerr << "Shader linking error of type: " << type << std::endl 168 | << info_log << std::endl; 169 | return false; 170 | } 171 | } 172 | return true; 173 | } 174 | 175 | } // namespace srt3d 176 | -------------------------------------------------------------------------------- /source/src/renderer_geometry.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | #define TINYOBJLOADER_IMPLEMENTATION 7 | #include 8 | 9 | namespace srt3d { 10 | 11 | int RendererGeometry::n_instances_ = 0; 12 | 13 | RendererGeometry::RendererGeometry(const std::string &name) : name_{name} {} 14 | 15 | RendererGeometry::~RendererGeometry() { 16 | if (initial_set_up_) { 17 | glfwMakeContextCurrent(window_); 18 | for (auto &render_data_body : render_data_bodies_) { 19 | DeleteGLVertexObjects(&render_data_body); 20 | } 21 | glfwMakeContextCurrent(0); 22 | glfwDestroyWindow(window_); 23 | window_ = nullptr; 24 | n_instances_--; 25 | if (n_instances_ == 0) glfwTerminate(); 26 | } 27 | } 28 | 29 | bool RendererGeometry::SetUp() { 30 | // Set up GLFW 31 | if (!initial_set_up_) { 32 | if (glfwInit() != GLFW_TRUE) { 33 | const char* description; 34 | glfwGetError(&description); 35 | std::cerr << "Failed to initialize GLFW: " << description << std::endl; 36 | return false; 37 | } 38 | 39 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 40 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 41 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 42 | glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); 43 | glfwWindowHint(GLFW_VISIBLE, GL_FALSE); 44 | 45 | window_ = glfwCreateWindow(640, 480, "window", nullptr, nullptr); 46 | if (window_ == nullptr) { 47 | std::cerr << "Failed to create GLFW window" << std::endl; 48 | glfwTerminate(); 49 | return false; 50 | } 51 | 52 | glfwMakeContextCurrent(window_); 53 | glewExperimental = true; 54 | if (glewInit() != GLEW_OK) { 55 | std::cerr << "Failed to initialize GLEW" << std::endl; 56 | glfwDestroyWindow(window_); 57 | window_ = nullptr; 58 | glfwTerminate(); 59 | return false; 60 | } 61 | glfwMakeContextCurrent(nullptr); 62 | 63 | n_instances_++; 64 | initial_set_up_ = true; 65 | } 66 | 67 | // Start with normal setup 68 | set_up_ = false; 69 | 70 | // Set up bodies 71 | glfwMakeContextCurrent(window_); 72 | for (auto &render_data_body : render_data_bodies_) { 73 | // Load vertices of mesh 74 | std::vector vertices; 75 | if (!LoadMeshIntoVertices(*render_data_body.body_ptr.get(), &vertices)) 76 | return false; 77 | render_data_body.n_vertices = unsigned(vertices.size()) / 6; 78 | 79 | // Create GL Vertex objects 80 | if (set_up_) DeleteGLVertexObjects(&render_data_body); 81 | CreateGLVertexObjects(vertices, &render_data_body); 82 | } 83 | glfwMakeContextCurrent(nullptr); 84 | 85 | set_up_ = true; 86 | return true; 87 | } 88 | 89 | bool RendererGeometry::AddBody(std::shared_ptr body_ptr, bool verbose) { 90 | const std::lock_guard lock{mutex_}; 91 | 92 | // Check if renderer geometry for body already exists 93 | for (auto &render_data_body : render_data_bodies_) { 94 | if (body_ptr->name() == render_data_body.body_ptr->name()) { 95 | if (verbose) 96 | std::cerr << "Body data " << body_ptr->name() << " already exists" 97 | << std::endl; 98 | return false; 99 | } 100 | } 101 | 102 | // Create data for body and assign parameters 103 | RenderDataBody render_data_body; 104 | render_data_body.body_ptr = std::move(body_ptr); 105 | if (set_up_) { 106 | // Load vertices of mesh 107 | std::vector vertices; 108 | if (!LoadMeshIntoVertices(*render_data_body.body_ptr.get(), &vertices)) 109 | return false; 110 | render_data_body.n_vertices = unsigned(vertices.size()) / 6; 111 | 112 | // Create GL Vertex objects 113 | glfwMakeContextCurrent(window_); 114 | CreateGLVertexObjects(vertices, &render_data_body); 115 | glfwMakeContextCurrent(nullptr); 116 | } 117 | 118 | // Add body data 119 | render_data_bodies_.push_back(std::move(render_data_body)); 120 | return true; 121 | } 122 | 123 | bool RendererGeometry::DeleteBody(const std::string &name, bool verbose) { 124 | const std::lock_guard lock{mutex_}; 125 | for (size_t i = 0; i < render_data_bodies_.size(); ++i) { 126 | if (name == render_data_bodies_[i].body_ptr->name()) { 127 | if (set_up_) { 128 | glfwMakeContextCurrent(window_); 129 | DeleteGLVertexObjects(&render_data_bodies_[i]); 130 | glfwMakeContextCurrent(nullptr); 131 | } 132 | render_data_bodies_.erase(begin(render_data_bodies_) + i); 133 | return true; 134 | } 135 | } 136 | if (verbose) 137 | std::cerr << "Body data \"" << name << "\" not found" << std::endl; 138 | return false; 139 | } 140 | 141 | void RendererGeometry::ClearBodies() { 142 | const std::lock_guard lock{mutex_}; 143 | if (set_up_) { 144 | glfwMakeContextCurrent(window_); 145 | for (auto &render_data_body : render_data_bodies_) { 146 | DeleteGLVertexObjects(&render_data_body); 147 | } 148 | glfwMakeContextCurrent(nullptr); 149 | } 150 | render_data_bodies_.clear(); 151 | } 152 | 153 | void RendererGeometry::MakeContextCurrent() { 154 | mutex_.lock(); 155 | glfwMakeContextCurrent(window_); 156 | } 157 | 158 | void RendererGeometry::DetachContext() { 159 | glfwMakeContextCurrent(nullptr); 160 | mutex_.unlock(); 161 | } 162 | 163 | const std::string &RendererGeometry::name() const { return name_; } 164 | 165 | const std::vector 166 | &RendererGeometry::render_data_bodies() const { 167 | return render_data_bodies_; 168 | } 169 | 170 | bool RendererGeometry::set_up() const { return set_up_; } 171 | 172 | bool RendererGeometry::LoadMeshIntoVertices(const Body &body, 173 | std::vector *vertices) { 174 | tinyobj::attrib_t attributes; 175 | std::vector shapes; 176 | std::vector materials; 177 | std::string warning; 178 | std::string error; 179 | 180 | if (!tinyobj::LoadObj(&attributes, &shapes, &materials, &warning, &error, 181 | body.geometry_path().string().c_str(), nullptr, true, 182 | false)) { 183 | std::cerr << "TinyObjLoader failed to load data from " 184 | << body.geometry_path() << std::endl; 185 | return false; 186 | } 187 | if (!error.empty()) std::cerr << error << std::endl; 188 | 189 | vertices->clear(); 190 | for (auto &shape : shapes) { 191 | size_t index_offset = 0; 192 | for (size_t f = 0; f < shape.mesh.num_face_vertices.size(); ++f) { 193 | if (shape.mesh.num_face_vertices[f] != 3) { 194 | std::cerr << "Mesh contains non triangle shapes" << std::endl; 195 | index_offset += shape.mesh.num_face_vertices[f]; 196 | continue; 197 | } 198 | 199 | // Extract triangle points 200 | std::array points; 201 | for (int v = 0; v < 3; ++v) { 202 | int idx = 3 * shape.mesh.indices[index_offset + v].vertex_index; 203 | if (body.geometry_counterclockwise()) { 204 | points[v](0) = float(attributes.vertices[idx + 0]); 205 | points[v](1) = float(attributes.vertices[idx + 1]); 206 | points[v](2) = float(attributes.vertices[idx + 2]); 207 | points[v] *= body.geometry_unit_in_meter(); 208 | } else { 209 | points[2 - v](0) = float(attributes.vertices[idx + 0]); 210 | points[2 - v](1) = float(attributes.vertices[idx + 1]); 211 | points[2 - v](2) = float(attributes.vertices[idx + 2]); 212 | points[2 - v] *= body.geometry_unit_in_meter(); 213 | } 214 | } 215 | 216 | // Calculate normal vector 217 | Eigen::Vector3f normal{ 218 | (points[2] - points[1]).cross(points[0] - points[1]).normalized()}; 219 | 220 | // Save data in vertices vector 221 | for (auto point : points) { 222 | vertices->insert(end(*vertices), point.data(), point.data() + 3); 223 | vertices->insert(end(*vertices), normal.data(), normal.data() + 3); 224 | } 225 | 226 | index_offset += 3; 227 | } 228 | } 229 | return true; 230 | } 231 | 232 | void RendererGeometry::CreateGLVertexObjects(const std::vector &vertices, 233 | RenderDataBody *render_data_body) { 234 | glGenVertexArrays(1, &render_data_body->vao); 235 | glBindVertexArray(render_data_body->vao); 236 | 237 | glGenBuffers(1, &render_data_body->vbo); 238 | glBindBuffer(GL_ARRAY_BUFFER, render_data_body->vbo); 239 | glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), 240 | &vertices.front(), GL_STATIC_DRAW); 241 | 242 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr); 243 | glEnableVertexAttribArray(0); 244 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 245 | (void *)(3 * sizeof(float))); 246 | glEnableVertexAttribArray(1); 247 | 248 | glBindBuffer(GL_ARRAY_BUFFER, 0); 249 | glBindVertexArray(0); 250 | } 251 | 252 | void RendererGeometry::DeleteGLVertexObjects(RenderDataBody *render_data_body) { 253 | glDeleteBuffers(1, &render_data_body->vbo); 254 | glDeleteVertexArrays(1, &render_data_body->vao); 255 | } 256 | 257 | } // namespace srt3d 258 | -------------------------------------------------------------------------------- /source/src/viewer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2021 Manuel Stoiber, German Aerospace Center (DLR) 3 | 4 | #include 5 | 6 | namespace srt3d { 7 | 8 | Viewer::Viewer(const std::string &name, std::shared_ptr camera_ptr) 9 | : name_{name}, camera_ptr_{std::move(camera_ptr)} {} 10 | 11 | void Viewer::set_name(const std::string &name) { name_ = name; } 12 | 13 | void Viewer::set_camera_ptr(std::shared_ptr camera_ptr) { 14 | camera_ptr_ = std::move(camera_ptr); 15 | set_up_ = false; 16 | } 17 | 18 | void Viewer::set_display_images(bool dispaly_images) { 19 | display_images_ = dispaly_images; 20 | } 21 | 22 | void Viewer::StartSavingImages(const std::filesystem::path &save_directory, 23 | const std::string &save_image_type) { 24 | save_images_ = true; 25 | save_directory_ = save_directory; 26 | save_image_type_ = save_image_type; 27 | } 28 | 29 | void Viewer::StopSavingImages() { save_images_ = false; } 30 | 31 | const std::string &Viewer::name() const { return name_; } 32 | 33 | std::shared_ptr Viewer::camera_ptr() const { return camera_ptr_; } 34 | 35 | std::shared_ptr Viewer::renderer_geometry_ptr() const { 36 | return nullptr; 37 | } 38 | 39 | bool Viewer::display_images() const { return display_images_; } 40 | 41 | bool Viewer::save_images() const { return save_images_; } 42 | 43 | bool Viewer::set_up() const { return set_up_; } 44 | 45 | void Viewer::DisplayAndSaveImage(int save_index, const cv::Mat &image) { 46 | if (display_images_) cv::imshow(name_, image); 47 | if (save_images_) { 48 | std::filesystem::path path{save_directory_ / 49 | (name_ + "_image_" + std::to_string(save_index) + 50 | "." + save_image_type_)}; 51 | cv::imwrite(path.string(), image); 52 | } 53 | } 54 | 55 | void Viewer::DisplayImage() { 56 | if (display_images_) cv::imshow(name_, viewer_image_); 57 | } 58 | 59 | const cv::Mat &Viewer::viewer_image() const { return viewer_image_; } 60 | 61 | } // namespace srt3d 62 | -------------------------------------------------------------------------------- /source/third_party/pybind11/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Wenzel Jakob , All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of 29 | external contributions to this project including patches, pull requests, etc. 30 | -------------------------------------------------------------------------------- /source/third_party/pybind11/README.rst: -------------------------------------------------------------------------------- 1 | .. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png 2 | :alt: pybind11 logo 3 | 4 | **pybind11 — Seamless operability between C++11 and Python** 5 | 6 | |Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status| 7 | 8 | |Repology| |PyPI package| |Conda-forge| |Python Versions| 9 | 10 | `Setuptools example `_ 11 | • `Scikit-build example `_ 12 | • `CMake example `_ 13 | 14 | .. start 15 | 16 | 17 | **pybind11** is a lightweight header-only library that exposes C++ types 18 | in Python and vice versa, mainly to create Python bindings of existing 19 | C++ code. Its goals and syntax are similar to the excellent 20 | `Boost.Python `_ 21 | library by David Abrahams: to minimize boilerplate code in traditional 22 | extension modules by inferring type information using compile-time 23 | introspection. 24 | 25 | The main issue with Boost.Python—and the reason for creating such a 26 | similar project—is Boost. Boost is an enormously large and complex suite 27 | of utility libraries that works with almost every C++ compiler in 28 | existence. This compatibility has its cost: arcane template tricks and 29 | workarounds are necessary to support the oldest and buggiest of compiler 30 | specimens. Now that C++11-compatible compilers are widely available, 31 | this heavy machinery has become an excessively large and unnecessary 32 | dependency. 33 | 34 | Think of this library as a tiny self-contained version of Boost.Python 35 | with everything stripped away that isn't relevant for binding 36 | generation. Without comments, the core header files only require ~4K 37 | lines of code and depend on Python (3.6+, or PyPy) and the C++ 38 | standard library. This compact implementation was possible thanks to 39 | some C++11 language features (specifically: tuples, lambda functions and 40 | variadic templates). Since its creation, this library has grown beyond 41 | Boost.Python in many ways, leading to dramatically simpler binding code in many 42 | common situations. 43 | 44 | Tutorial and reference documentation is provided at 45 | `pybind11.readthedocs.io `_. 46 | A PDF version of the manual is available 47 | `here `_. 48 | And the source code is always available at 49 | `github.com/pybind/pybind11 `_. 50 | 51 | 52 | Core features 53 | ------------- 54 | 55 | 56 | pybind11 can map the following core C++ features to Python: 57 | 58 | - Functions accepting and returning custom data structures per value, 59 | reference, or pointer 60 | - Instance methods and static methods 61 | - Overloaded functions 62 | - Instance attributes and static attributes 63 | - Arbitrary exception types 64 | - Enumerations 65 | - Callbacks 66 | - Iterators and ranges 67 | - Custom operators 68 | - Single and multiple inheritance 69 | - STL data structures 70 | - Smart pointers with reference counting like ``std::shared_ptr`` 71 | - Internal references with correct reference counting 72 | - C++ classes with virtual (and pure virtual) methods can be extended 73 | in Python 74 | - Integrated NumPy support (NumPy 2 requires pybind11 2.12+) 75 | 76 | Goodies 77 | ------- 78 | 79 | In addition to the core functionality, pybind11 provides some extra 80 | goodies: 81 | 82 | - Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic 83 | interface (pybind11 2.9 was the last version to support Python 2 and 3.5). 84 | 85 | - It is possible to bind C++11 lambda functions with captured 86 | variables. The lambda capture data is stored inside the resulting 87 | Python function object. 88 | 89 | - pybind11 uses C++11 move constructors and move assignment operators 90 | whenever possible to efficiently transfer custom data types. 91 | 92 | - It's easy to expose the internal storage of custom data types through 93 | Pythons' buffer protocols. This is handy e.g. for fast conversion 94 | between C++ matrix classes like Eigen and NumPy without expensive 95 | copy operations. 96 | 97 | - pybind11 can automatically vectorize functions so that they are 98 | transparently applied to all entries of one or more NumPy array 99 | arguments. 100 | 101 | - Python's slice-based access and assignment operations can be 102 | supported with just a few lines of code. 103 | 104 | - Everything is contained in just a few header files; there is no need 105 | to link against any additional libraries. 106 | 107 | - Binaries are generally smaller by a factor of at least 2 compared to 108 | equivalent bindings generated by Boost.Python. A recent pybind11 109 | conversion of PyRosetta, an enormous Boost.Python binding project, 110 | `reported `_ 111 | a binary size reduction of **5.4x** and compile time reduction by 112 | **5.8x**. 113 | 114 | - Function signatures are precomputed at compile time (using 115 | ``constexpr``), leading to smaller binaries. 116 | 117 | - With little extra effort, C++ types can be pickled and unpickled 118 | similar to regular Python objects. 119 | 120 | Supported compilers 121 | ------------------- 122 | 123 | 1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or 124 | newer) 125 | 2. GCC 4.8 or newer 126 | 3. Microsoft Visual Studio 2017 or newer 127 | 4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) 128 | 5. Cygwin/GCC (previously tested on 2.5.1) 129 | 6. NVCC (CUDA 11.0 tested in CI) 130 | 7. NVIDIA PGI (20.9 tested in CI) 131 | 132 | About 133 | ----- 134 | 135 | This project was created by `Wenzel 136 | Jakob `_. Significant features and/or 137 | improvements to the code were contributed by Jonas Adler, Lori A. Burns, 138 | Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel 139 | Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko, 140 | Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim 141 | Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart. 142 | 143 | We thank Google for a generous financial contribution to the continuous 144 | integration infrastructure used by this project. 145 | 146 | 147 | Contributing 148 | ~~~~~~~~~~~~ 149 | 150 | See the `contributing 151 | guide `_ 152 | for information on building and contributing to pybind11. 153 | 154 | License 155 | ~~~~~~~ 156 | 157 | pybind11 is provided under a BSD-style license that can be found in the 158 | `LICENSE `_ 159 | file. By using, distributing, or contributing to this project, you agree 160 | to the terms and conditions of this license. 161 | 162 | .. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest 163 | :target: http://pybind11.readthedocs.org/en/latest 164 | .. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg 165 | :target: http://pybind11.readthedocs.org/en/stable 166 | .. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg 167 | :target: https://gitter.im/pybind/Lobby 168 | .. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg 169 | :target: https://github.com/pybind/pybind11/actions 170 | .. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true 171 | :target: https://ci.appveyor.com/project/wjakob/pybind11 172 | .. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg 173 | :target: https://pypi.org/project/pybind11/ 174 | .. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg 175 | :target: https://github.com/conda-forge/pybind11-feedstock 176 | .. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg 177 | :target: https://repology.org/project/python:pybind11/versions 178 | .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg 179 | :target: https://pypi.org/project/pybind11/ 180 | .. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github 181 | :target: https://github.com/pybind/pybind11/discussions 182 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/buffer_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/buffer_info.h: Python buffer object interface 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "detail/common.h" 13 | 14 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | 16 | PYBIND11_NAMESPACE_BEGIN(detail) 17 | 18 | // Default, C-style strides 19 | inline std::vector c_strides(const std::vector &shape, ssize_t itemsize) { 20 | auto ndim = shape.size(); 21 | std::vector strides(ndim, itemsize); 22 | if (ndim > 0) { 23 | for (size_t i = ndim - 1; i > 0; --i) { 24 | strides[i - 1] = strides[i] * shape[i]; 25 | } 26 | } 27 | return strides; 28 | } 29 | 30 | // F-style strides; default when constructing an array_t with `ExtraFlags & f_style` 31 | inline std::vector f_strides(const std::vector &shape, ssize_t itemsize) { 32 | auto ndim = shape.size(); 33 | std::vector strides(ndim, itemsize); 34 | for (size_t i = 1; i < ndim; ++i) { 35 | strides[i] = strides[i - 1] * shape[i - 1]; 36 | } 37 | return strides; 38 | } 39 | 40 | template 41 | struct compare_buffer_info; 42 | 43 | PYBIND11_NAMESPACE_END(detail) 44 | 45 | /// Information record describing a Python buffer object 46 | struct buffer_info { 47 | void *ptr = nullptr; // Pointer to the underlying storage 48 | ssize_t itemsize = 0; // Size of individual items in bytes 49 | ssize_t size = 0; // Total number of entries 50 | std::string format; // For homogeneous buffers, this should be set to 51 | // format_descriptor::format() 52 | ssize_t ndim = 0; // Number of dimensions 53 | std::vector shape; // Shape of the tensor (1 entry per dimension) 54 | std::vector strides; // Number of bytes between adjacent entries 55 | // (for each per dimension) 56 | bool readonly = false; // flag to indicate if the underlying storage may be written to 57 | 58 | buffer_info() = default; 59 | 60 | buffer_info(void *ptr, 61 | ssize_t itemsize, 62 | const std::string &format, 63 | ssize_t ndim, 64 | detail::any_container shape_in, 65 | detail::any_container strides_in, 66 | bool readonly = false) 67 | : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), 68 | shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { 69 | if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) { 70 | pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); 71 | } 72 | for (size_t i = 0; i < (size_t) ndim; ++i) { 73 | size *= shape[i]; 74 | } 75 | } 76 | 77 | template 78 | buffer_info(T *ptr, 79 | detail::any_container shape_in, 80 | detail::any_container strides_in, 81 | bool readonly = false) 82 | : buffer_info(private_ctr_tag(), 83 | ptr, 84 | sizeof(T), 85 | format_descriptor::format(), 86 | static_cast(shape_in->size()), 87 | std::move(shape_in), 88 | std::move(strides_in), 89 | readonly) {} 90 | 91 | buffer_info(void *ptr, 92 | ssize_t itemsize, 93 | const std::string &format, 94 | ssize_t size, 95 | bool readonly = false) 96 | : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {} 97 | 98 | template 99 | buffer_info(T *ptr, ssize_t size, bool readonly = false) 100 | : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) {} 101 | 102 | template 103 | buffer_info(const T *ptr, ssize_t size, bool readonly = true) 104 | : buffer_info( 105 | const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) {} 106 | 107 | explicit buffer_info(Py_buffer *view, bool ownview = true) 108 | : buffer_info( 109 | view->buf, 110 | view->itemsize, 111 | view->format, 112 | view->ndim, 113 | {view->shape, view->shape + view->ndim}, 114 | /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects 115 | * ignore this flag and return a view with NULL strides. 116 | * When strides are NULL, build them manually. */ 117 | view->strides 118 | ? std::vector(view->strides, view->strides + view->ndim) 119 | : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), 120 | (view->readonly != 0)) { 121 | // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) 122 | this->m_view = view; 123 | // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) 124 | this->ownview = ownview; 125 | } 126 | 127 | buffer_info(const buffer_info &) = delete; 128 | buffer_info &operator=(const buffer_info &) = delete; 129 | 130 | buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } 131 | 132 | buffer_info &operator=(buffer_info &&rhs) noexcept { 133 | ptr = rhs.ptr; 134 | itemsize = rhs.itemsize; 135 | size = rhs.size; 136 | format = std::move(rhs.format); 137 | ndim = rhs.ndim; 138 | shape = std::move(rhs.shape); 139 | strides = std::move(rhs.strides); 140 | std::swap(m_view, rhs.m_view); 141 | std::swap(ownview, rhs.ownview); 142 | readonly = rhs.readonly; 143 | return *this; 144 | } 145 | 146 | ~buffer_info() { 147 | if (m_view && ownview) { 148 | PyBuffer_Release(m_view); 149 | delete m_view; 150 | } 151 | } 152 | 153 | Py_buffer *view() const { return m_view; } 154 | Py_buffer *&view() { return m_view; } 155 | 156 | /* True if the buffer item type is equivalent to `T`. */ 157 | // To define "equivalent" by example: 158 | // `buffer_info::item_type_is_equivalent_to(b)` and 159 | // `buffer_info::item_type_is_equivalent_to(b)` may both be true 160 | // on some platforms, but `int` and `unsigned` will never be equivalent. 161 | // For the ground truth, please inspect `detail::compare_buffer_info<>`. 162 | template 163 | bool item_type_is_equivalent_to() const { 164 | return detail::compare_buffer_info::compare(*this); 165 | } 166 | 167 | private: 168 | struct private_ctr_tag {}; 169 | 170 | buffer_info(private_ctr_tag, 171 | void *ptr, 172 | ssize_t itemsize, 173 | const std::string &format, 174 | ssize_t ndim, 175 | detail::any_container &&shape_in, 176 | detail::any_container &&strides_in, 177 | bool readonly) 178 | : buffer_info( 179 | ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} 180 | 181 | Py_buffer *m_view = nullptr; 182 | bool ownview = false; 183 | }; 184 | 185 | PYBIND11_NAMESPACE_BEGIN(detail) 186 | 187 | template 188 | struct compare_buffer_info { 189 | static bool compare(const buffer_info &b) { 190 | // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *` 191 | return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); 192 | } 193 | }; 194 | 195 | template 196 | struct compare_buffer_info::value>> { 197 | static bool compare(const buffer_info &b) { 198 | return (size_t) b.itemsize == sizeof(T) 199 | && (b.format == format_descriptor::value 200 | || ((sizeof(T) == sizeof(long)) 201 | && b.format == (std::is_unsigned::value ? "L" : "l")) 202 | || ((sizeof(T) == sizeof(size_t)) 203 | && b.format == (std::is_unsigned::value ? "N" : "n"))); 204 | } 205 | }; 206 | 207 | PYBIND11_NAMESPACE_END(detail) 208 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 209 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/chrono.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime 3 | 4 | Copyright (c) 2016 Trent Houliston and 5 | Wenzel Jakob 6 | 7 | All rights reserved. Use of this source code is governed by a 8 | BSD-style license that can be found in the LICENSE file. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "pybind11.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 22 | PYBIND11_NAMESPACE_BEGIN(detail) 23 | 24 | template 25 | class duration_caster { 26 | public: 27 | using rep = typename type::rep; 28 | using period = typename type::period; 29 | 30 | // signed 25 bits required by the standard. 31 | using days = std::chrono::duration>; 32 | 33 | bool load(handle src, bool) { 34 | using namespace std::chrono; 35 | 36 | // Lazy initialise the PyDateTime import 37 | if (!PyDateTimeAPI) { 38 | PyDateTime_IMPORT; 39 | } 40 | 41 | if (!src) { 42 | return false; 43 | } 44 | // If invoked with datetime.delta object 45 | if (PyDelta_Check(src.ptr())) { 46 | value = type(duration_cast>( 47 | days(PyDateTime_DELTA_GET_DAYS(src.ptr())) 48 | + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) 49 | + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); 50 | return true; 51 | } 52 | // If invoked with a float we assume it is seconds and convert 53 | if (PyFloat_Check(src.ptr())) { 54 | value = type(duration_cast>( 55 | duration(PyFloat_AsDouble(src.ptr())))); 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | // If this is a duration just return it back 62 | static const std::chrono::duration & 63 | get_duration(const std::chrono::duration &src) { 64 | return src; 65 | } 66 | 67 | // If this is a time_point get the time_since_epoch 68 | template 69 | static std::chrono::duration 70 | get_duration(const std::chrono::time_point> &src) { 71 | return src.time_since_epoch(); 72 | } 73 | 74 | static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) { 75 | using namespace std::chrono; 76 | 77 | // Use overloaded function to get our duration from our source 78 | // Works out if it is a duration or time_point and get the duration 79 | auto d = get_duration(src); 80 | 81 | // Lazy initialise the PyDateTime import 82 | if (!PyDateTimeAPI) { 83 | PyDateTime_IMPORT; 84 | } 85 | 86 | // Declare these special duration types so the conversions happen with the correct 87 | // primitive types (int) 88 | using dd_t = duration>; 89 | using ss_t = duration>; 90 | using us_t = duration; 91 | 92 | auto dd = duration_cast(d); 93 | auto subd = d - dd; 94 | auto ss = duration_cast(subd); 95 | auto us = duration_cast(subd - ss); 96 | return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); 97 | } 98 | 99 | PYBIND11_TYPE_CASTER(type, const_name("datetime.timedelta")); 100 | }; 101 | 102 | inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) { 103 | #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER) 104 | if (localtime_s(buf, time)) 105 | return nullptr; 106 | return buf; 107 | #else 108 | static std::mutex mtx; 109 | std::lock_guard lock(mtx); 110 | std::tm *tm_ptr = std::localtime(time); 111 | if (tm_ptr != nullptr) { 112 | *buf = *tm_ptr; 113 | } 114 | return tm_ptr; 115 | #endif 116 | } 117 | 118 | // This is for casting times on the system clock into datetime.datetime instances 119 | template 120 | class type_caster> { 121 | public: 122 | using type = std::chrono::time_point; 123 | bool load(handle src, bool) { 124 | using namespace std::chrono; 125 | 126 | // Lazy initialise the PyDateTime import 127 | if (!PyDateTimeAPI) { 128 | PyDateTime_IMPORT; 129 | } 130 | 131 | if (!src) { 132 | return false; 133 | } 134 | 135 | std::tm cal; 136 | microseconds msecs; 137 | 138 | if (PyDateTime_Check(src.ptr())) { 139 | cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); 140 | cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); 141 | cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); 142 | cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); 143 | cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; 144 | cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; 145 | cal.tm_isdst = -1; 146 | msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); 147 | } else if (PyDate_Check(src.ptr())) { 148 | cal.tm_sec = 0; 149 | cal.tm_min = 0; 150 | cal.tm_hour = 0; 151 | cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); 152 | cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; 153 | cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; 154 | cal.tm_isdst = -1; 155 | msecs = microseconds(0); 156 | } else if (PyTime_Check(src.ptr())) { 157 | cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr()); 158 | cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr()); 159 | cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr()); 160 | cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70) 161 | cal.tm_mon = 0; // represents 1-Jan-1970, which is the first 162 | cal.tm_year = 70; // earliest available date for Python's datetime 163 | cal.tm_isdst = -1; 164 | msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())); 165 | } else { 166 | return false; 167 | } 168 | 169 | value = time_point_cast(system_clock::from_time_t(std::mktime(&cal)) + msecs); 170 | return true; 171 | } 172 | 173 | static handle cast(const std::chrono::time_point &src, 174 | return_value_policy /* policy */, 175 | handle /* parent */) { 176 | using namespace std::chrono; 177 | 178 | // Lazy initialise the PyDateTime import 179 | if (!PyDateTimeAPI) { 180 | PyDateTime_IMPORT; 181 | } 182 | 183 | // Get out microseconds, and make sure they are positive, to avoid bug in eastern 184 | // hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417) 185 | using us_t = duration; 186 | auto us = duration_cast(src.time_since_epoch() % seconds(1)); 187 | if (us.count() < 0) { 188 | us += seconds(1); 189 | } 190 | 191 | // Subtract microseconds BEFORE `system_clock::to_time_t`, because: 192 | // > If std::time_t has lower precision, it is implementation-defined whether the value is 193 | // rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t) 194 | std::time_t tt 195 | = system_clock::to_time_t(time_point_cast(src - us)); 196 | 197 | std::tm localtime; 198 | std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime); 199 | if (!localtime_ptr) { 200 | throw cast_error("Unable to represent system_clock in local time"); 201 | } 202 | return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, 203 | localtime.tm_mon + 1, 204 | localtime.tm_mday, 205 | localtime.tm_hour, 206 | localtime.tm_min, 207 | localtime.tm_sec, 208 | us.count()); 209 | } 210 | PYBIND11_TYPE_CASTER(type, const_name("datetime.datetime")); 211 | }; 212 | 213 | // Other clocks that are not the system clock are not measured as datetime.datetime objects 214 | // since they are not measured on calendar time. So instead we just make them timedeltas 215 | // Or if they have passed us a time as a float we convert that 216 | template 217 | class type_caster> 218 | : public duration_caster> {}; 219 | 220 | template 221 | class type_caster> 222 | : public duration_caster> {}; 223 | 224 | PYBIND11_NAMESPACE_END(detail) 225 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 226 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/common.h: -------------------------------------------------------------------------------- 1 | #include "detail/common.h" 2 | #warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." 3 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/complex.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/complex.h: Complex number support 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "pybind11.h" 13 | 14 | #include 15 | 16 | /// glibc defines I as a macro which breaks things, e.g., boost template names 17 | #ifdef I 18 | # undef I 19 | #endif 20 | 21 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 22 | 23 | template 24 | struct format_descriptor, detail::enable_if_t::value>> { 25 | static constexpr const char c = format_descriptor::c; 26 | static constexpr const char value[3] = {'Z', c, '\0'}; 27 | static std::string format() { return std::string(value); } 28 | }; 29 | 30 | #ifndef PYBIND11_CPP17 31 | 32 | template 33 | constexpr const char 34 | format_descriptor, 35 | detail::enable_if_t::value>>::value[3]; 36 | 37 | #endif 38 | 39 | PYBIND11_NAMESPACE_BEGIN(detail) 40 | 41 | template 42 | struct is_fmt_numeric, detail::enable_if_t::value>> { 43 | static constexpr bool value = true; 44 | static constexpr int index = is_fmt_numeric::index + 3; 45 | }; 46 | 47 | template 48 | class type_caster> { 49 | public: 50 | bool load(handle src, bool convert) { 51 | if (!src) { 52 | return false; 53 | } 54 | if (!convert && !PyComplex_Check(src.ptr())) { 55 | return false; 56 | } 57 | Py_complex result = PyComplex_AsCComplex(src.ptr()); 58 | if (result.real == -1.0 && PyErr_Occurred()) { 59 | PyErr_Clear(); 60 | return false; 61 | } 62 | value = std::complex((T) result.real, (T) result.imag); 63 | return true; 64 | } 65 | 66 | static handle 67 | cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { 68 | return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); 69 | } 70 | 71 | PYBIND11_TYPE_CASTER(std::complex, const_name("complex")); 72 | }; 73 | PYBIND11_NAMESPACE_END(detail) 74 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 75 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/detail/descr.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "common.h" 13 | 14 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | PYBIND11_NAMESPACE_BEGIN(detail) 16 | 17 | #if !defined(_MSC_VER) 18 | # define PYBIND11_DESCR_CONSTEXPR static constexpr 19 | #else 20 | # define PYBIND11_DESCR_CONSTEXPR const 21 | #endif 22 | 23 | /* Concatenate type signatures at compile time */ 24 | template 25 | struct descr { 26 | char text[N + 1]{'\0'}; 27 | 28 | constexpr descr() = default; 29 | // NOLINTNEXTLINE(google-explicit-constructor) 30 | constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence()) {} 31 | 32 | template 33 | constexpr descr(char const (&s)[N + 1], index_sequence) : text{s[Is]..., '\0'} {} 34 | 35 | template 36 | // NOLINTNEXTLINE(google-explicit-constructor) 37 | constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} {} 38 | 39 | static constexpr std::array types() { 40 | return {{&typeid(Ts)..., nullptr}}; 41 | } 42 | }; 43 | 44 | template 45 | constexpr descr plus_impl(const descr &a, 46 | const descr &b, 47 | index_sequence, 48 | index_sequence) { 49 | PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b); 50 | return {a.text[Is1]..., b.text[Is2]...}; 51 | } 52 | 53 | template 54 | constexpr descr operator+(const descr &a, 55 | const descr &b) { 56 | return plus_impl(a, b, make_index_sequence(), make_index_sequence()); 57 | } 58 | 59 | template 60 | constexpr descr const_name(char const (&text)[N]) { 61 | return descr(text); 62 | } 63 | constexpr descr<0> const_name(char const (&)[1]) { return {}; } 64 | 65 | template 66 | struct int_to_str : int_to_str {}; 67 | template 68 | struct int_to_str<0, Digits...> { 69 | // WARNING: This only works with C++17 or higher. 70 | static constexpr auto digits = descr(('0' + Digits)...); 71 | }; 72 | 73 | // Ternary description (like std::conditional) 74 | template 75 | constexpr enable_if_t> const_name(char const (&text1)[N1], char const (&)[N2]) { 76 | return const_name(text1); 77 | } 78 | template 79 | constexpr enable_if_t> const_name(char const (&)[N1], char const (&text2)[N2]) { 80 | return const_name(text2); 81 | } 82 | 83 | template 84 | constexpr enable_if_t const_name(const T1 &d, const T2 &) { 85 | return d; 86 | } 87 | template 88 | constexpr enable_if_t const_name(const T1 &, const T2 &d) { 89 | return d; 90 | } 91 | 92 | template 93 | auto constexpr const_name() -> remove_cv_t::digits)> { 94 | return int_to_str::digits; 95 | } 96 | 97 | template 98 | constexpr descr<1, Type> const_name() { 99 | return {'%'}; 100 | } 101 | 102 | // If "_" is defined as a macro, py::detail::_ cannot be provided. 103 | // It is therefore best to use py::detail::const_name universally. 104 | // This block is for backward compatibility only. 105 | // (The const_name code is repeated to avoid introducing a "_" #define ourselves.) 106 | #ifndef _ 107 | # define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY 108 | template 109 | constexpr descr _(char const (&text)[N]) { 110 | return const_name(text); 111 | } 112 | template 113 | constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { 114 | return const_name(text1, text2); 115 | } 116 | template 117 | constexpr enable_if_t> _(char const (&text1)[N1], char const (&text2)[N2]) { 118 | return const_name(text1, text2); 119 | } 120 | template 121 | constexpr enable_if_t _(const T1 &d1, const T2 &d2) { 122 | return const_name(d1, d2); 123 | } 124 | template 125 | constexpr enable_if_t _(const T1 &d1, const T2 &d2) { 126 | return const_name(d1, d2); 127 | } 128 | 129 | template 130 | auto constexpr _() -> remove_cv_t::digits)> { 131 | return const_name(); 132 | } 133 | template 134 | constexpr descr<1, Type> _() { 135 | return const_name(); 136 | } 137 | #endif // #ifndef _ 138 | 139 | constexpr descr<0> concat() { return {}; } 140 | 141 | template 142 | constexpr descr concat(const descr &descr) { 143 | return descr; 144 | } 145 | 146 | #ifdef __cpp_fold_expressions 147 | template 148 | constexpr descr operator,(const descr &a, 149 | const descr &b) { 150 | return a + const_name(", ") + b; 151 | } 152 | 153 | template 154 | constexpr auto concat(const descr &d, const Args &...args) { 155 | return (d, ..., args); 156 | } 157 | #else 158 | template 159 | constexpr auto concat(const descr &d, 160 | const Args &...args) -> decltype(std::declval>() 161 | + concat(args...)) { 162 | return d + const_name(", ") + concat(args...); 163 | } 164 | #endif 165 | 166 | template 167 | constexpr descr type_descr(const descr &descr) { 168 | return const_name("{") + descr + const_name("}"); 169 | } 170 | 171 | PYBIND11_NAMESPACE_END(detail) 172 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 173 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/detail/typeid.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/detail/typeid.h: Compiler-independent access to type identifiers 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #if defined(__GNUG__) 16 | # include 17 | #endif 18 | 19 | #include "common.h" 20 | 21 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 22 | PYBIND11_NAMESPACE_BEGIN(detail) 23 | 24 | /// Erase all occurrences of a substring 25 | inline void erase_all(std::string &string, const std::string &search) { 26 | for (size_t pos = 0;;) { 27 | pos = string.find(search, pos); 28 | if (pos == std::string::npos) { 29 | break; 30 | } 31 | string.erase(pos, search.length()); 32 | } 33 | } 34 | 35 | PYBIND11_NOINLINE void clean_type_id(std::string &name) { 36 | #if defined(__GNUG__) 37 | int status = 0; 38 | std::unique_ptr res{ 39 | abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free}; 40 | if (status == 0) { 41 | name = res.get(); 42 | } 43 | #else 44 | detail::erase_all(name, "class "); 45 | detail::erase_all(name, "struct "); 46 | detail::erase_all(name, "enum "); 47 | #endif 48 | detail::erase_all(name, "pybind11::"); 49 | } 50 | 51 | inline std::string clean_type_id(const char *typeid_name) { 52 | std::string name(typeid_name); 53 | detail::clean_type_id(name); 54 | return name; 55 | } 56 | 57 | PYBIND11_NAMESPACE_END(detail) 58 | 59 | /// Return a string representation of a C++ type 60 | template 61 | static std::string type_id() { 62 | return detail::clean_type_id(typeid(T).name()); 63 | } 64 | 65 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 66 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/eigen.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "eigen/matrix.h" 13 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/eigen/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 The pybind Community. 2 | 3 | #pragma once 4 | 5 | // Common message for `static_assert()`s, which are useful to easily 6 | // preempt much less obvious errors. 7 | #define PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED \ 8 | "Pointer types (in particular `PyObject *`) are not supported as scalar types for Eigen " \ 9 | "types." 10 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/eval.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/eval.h: Support for evaluating Python expressions and statements 3 | from strings and files 4 | 5 | Copyright (c) 2016 Klemens Morgenstern and 6 | Wenzel Jakob 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE file. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "pybind11.h" 15 | 16 | #include 17 | 18 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 19 | PYBIND11_NAMESPACE_BEGIN(detail) 20 | 21 | inline void ensure_builtins_in_globals(object &global) { 22 | #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000 23 | // Running exec and eval adds `builtins` module under `__builtins__` key to 24 | // globals if not yet present. Python 3.8 made PyRun_String behave 25 | // similarly. Let's also do that for older versions, for consistency. This 26 | // was missing from PyPy3.8 7.3.7. 27 | if (!global.contains("__builtins__")) 28 | global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE); 29 | #else 30 | (void) global; 31 | #endif 32 | } 33 | 34 | PYBIND11_NAMESPACE_END(detail) 35 | 36 | enum eval_mode { 37 | /// Evaluate a string containing an isolated expression 38 | eval_expr, 39 | 40 | /// Evaluate a string containing a single statement. Returns \c none 41 | eval_single_statement, 42 | 43 | /// Evaluate a string containing a sequence of statement. Returns \c none 44 | eval_statements 45 | }; 46 | 47 | template 48 | object eval(const str &expr, object global = globals(), object local = object()) { 49 | if (!local) { 50 | local = global; 51 | } 52 | 53 | detail::ensure_builtins_in_globals(global); 54 | 55 | /* PyRun_String does not accept a PyObject / encoding specifier, 56 | this seems to be the only alternative */ 57 | std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; 58 | 59 | int start = 0; 60 | switch (mode) { 61 | case eval_expr: 62 | start = Py_eval_input; 63 | break; 64 | case eval_single_statement: 65 | start = Py_single_input; 66 | break; 67 | case eval_statements: 68 | start = Py_file_input; 69 | break; 70 | default: 71 | pybind11_fail("invalid evaluation mode"); 72 | } 73 | 74 | PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); 75 | if (!result) { 76 | throw error_already_set(); 77 | } 78 | return reinterpret_steal(result); 79 | } 80 | 81 | template 82 | object eval(const char (&s)[N], object global = globals(), object local = object()) { 83 | /* Support raw string literals by removing common leading whitespace */ 84 | auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s); 85 | return eval(expr, std::move(global), std::move(local)); 86 | } 87 | 88 | inline void exec(const str &expr, object global = globals(), object local = object()) { 89 | eval(expr, std::move(global), std::move(local)); 90 | } 91 | 92 | template 93 | void exec(const char (&s)[N], object global = globals(), object local = object()) { 94 | eval(s, std::move(global), std::move(local)); 95 | } 96 | 97 | #if defined(PYPY_VERSION) 98 | template 99 | object eval_file(str, object, object) { 100 | pybind11_fail("eval_file not supported in PyPy3. Use eval"); 101 | } 102 | template 103 | object eval_file(str, object) { 104 | pybind11_fail("eval_file not supported in PyPy3. Use eval"); 105 | } 106 | template 107 | object eval_file(str) { 108 | pybind11_fail("eval_file not supported in PyPy3. Use eval"); 109 | } 110 | #else 111 | template 112 | object eval_file(str fname, object global = globals(), object local = object()) { 113 | if (!local) { 114 | local = global; 115 | } 116 | 117 | detail::ensure_builtins_in_globals(global); 118 | 119 | int start = 0; 120 | switch (mode) { 121 | case eval_expr: 122 | start = Py_eval_input; 123 | break; 124 | case eval_single_statement: 125 | start = Py_single_input; 126 | break; 127 | case eval_statements: 128 | start = Py_file_input; 129 | break; 130 | default: 131 | pybind11_fail("invalid evaluation mode"); 132 | } 133 | 134 | int closeFile = 1; 135 | std::string fname_str = (std::string) fname; 136 | FILE *f = _Py_fopen_obj(fname.ptr(), "r"); 137 | if (!f) { 138 | PyErr_Clear(); 139 | pybind11_fail("File \"" + fname_str + "\" could not be opened!"); 140 | } 141 | 142 | if (!global.contains("__file__")) { 143 | global["__file__"] = std::move(fname); 144 | } 145 | 146 | PyObject *result 147 | = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile); 148 | 149 | if (!result) { 150 | throw error_already_set(); 151 | } 152 | return reinterpret_steal(result); 153 | } 154 | #endif 155 | 156 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 157 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/functional.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/functional.h: std::function<> support 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "pybind11.h" 13 | 14 | #include 15 | 16 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 17 | PYBIND11_NAMESPACE_BEGIN(detail) 18 | 19 | template 20 | struct type_caster> { 21 | using type = std::function; 22 | using retval_type = conditional_t::value, void_type, Return>; 23 | using function_type = Return (*)(Args...); 24 | 25 | public: 26 | bool load(handle src, bool convert) { 27 | if (src.is_none()) { 28 | // Defer accepting None to other overloads (if we aren't in convert mode): 29 | if (!convert) { 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | if (!isinstance(src)) { 36 | return false; 37 | } 38 | 39 | auto func = reinterpret_borrow(src); 40 | 41 | /* 42 | When passing a C++ function as an argument to another C++ 43 | function via Python, every function call would normally involve 44 | a full C++ -> Python -> C++ roundtrip, which can be prohibitive. 45 | Here, we try to at least detect the case where the function is 46 | stateless (i.e. function pointer or lambda function without 47 | captured variables), in which case the roundtrip can be avoided. 48 | */ 49 | if (auto cfunc = func.cpp_function()) { 50 | auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr()); 51 | if (cfunc_self == nullptr) { 52 | PyErr_Clear(); 53 | } else if (isinstance(cfunc_self)) { 54 | auto c = reinterpret_borrow(cfunc_self); 55 | 56 | function_record *rec = nullptr; 57 | // Check that we can safely reinterpret the capsule into a function_record 58 | if (detail::is_function_record_capsule(c)) { 59 | rec = c.get_pointer(); 60 | } 61 | 62 | while (rec != nullptr) { 63 | if (rec->is_stateless 64 | && same_type(typeid(function_type), 65 | *reinterpret_cast(rec->data[1]))) { 66 | struct capture { 67 | function_type f; 68 | }; 69 | value = ((capture *) &rec->data)->f; 70 | return true; 71 | } 72 | rec = rec->next; 73 | } 74 | } 75 | // PYPY segfaults here when passing builtin function like sum. 76 | // Raising an fail exception here works to prevent the segfault, but only on gcc. 77 | // See PR #1413 for full details 78 | } 79 | 80 | // ensure GIL is held during functor destruction 81 | struct func_handle { 82 | function f; 83 | #if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17)) 84 | // This triggers a syntax error under very special conditions (very weird indeed). 85 | explicit 86 | #endif 87 | func_handle(function &&f_) noexcept 88 | : f(std::move(f_)) { 89 | } 90 | func_handle(const func_handle &f_) { operator=(f_); } 91 | func_handle &operator=(const func_handle &f_) { 92 | gil_scoped_acquire acq; 93 | f = f_.f; 94 | return *this; 95 | } 96 | ~func_handle() { 97 | gil_scoped_acquire acq; 98 | function kill_f(std::move(f)); 99 | } 100 | }; 101 | 102 | // to emulate 'move initialization capture' in C++11 103 | struct func_wrapper { 104 | func_handle hfunc; 105 | explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {} 106 | Return operator()(Args... args) const { 107 | gil_scoped_acquire acq; 108 | // casts the returned object as a rvalue to the return type 109 | return hfunc.f(std::forward(args)...).template cast(); 110 | } 111 | }; 112 | 113 | value = func_wrapper(func_handle(std::move(func))); 114 | return true; 115 | } 116 | 117 | template 118 | static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { 119 | if (!f_) { 120 | return none().release(); 121 | } 122 | 123 | auto result = f_.template target(); 124 | if (result) { 125 | return cpp_function(*result, policy).release(); 126 | } 127 | return cpp_function(std::forward(f_), policy).release(); 128 | } 129 | 130 | PYBIND11_TYPE_CASTER(type, 131 | const_name("Callable[[") 132 | + ::pybind11::detail::concat(make_caster::name...) 133 | + const_name("], ") + make_caster::name 134 | + const_name("]")); 135 | }; 136 | 137 | PYBIND11_NAMESPACE_END(detail) 138 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 139 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/gil.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/gil.h: RAII helpers for managing the GIL 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "detail/common.h" 13 | 14 | #include 15 | 16 | #if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) 17 | # include "detail/internals.h" 18 | #endif 19 | 20 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 21 | 22 | PYBIND11_NAMESPACE_BEGIN(detail) 23 | 24 | // forward declarations 25 | PyThreadState *get_thread_state_unchecked(); 26 | 27 | PYBIND11_NAMESPACE_END(detail) 28 | 29 | #if defined(WITH_THREAD) 30 | 31 | # if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) 32 | 33 | /* The functions below essentially reproduce the PyGILState_* API using a RAII 34 | * pattern, but there are a few important differences: 35 | * 36 | * 1. When acquiring the GIL from an non-main thread during the finalization 37 | * phase, the GILState API blindly terminates the calling thread, which 38 | * is often not what is wanted. This API does not do this. 39 | * 40 | * 2. The gil_scoped_release function can optionally cut the relationship 41 | * of a PyThreadState and its associated thread, which allows moving it to 42 | * another thread (this is a fairly rare/advanced use case). 43 | * 44 | * 3. The reference count of an acquired thread state can be controlled. This 45 | * can be handy to prevent cases where callbacks issued from an external 46 | * thread would otherwise constantly construct and destroy thread state data 47 | * structures. 48 | * 49 | * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an 50 | * example which uses features 2 and 3 to migrate the Python thread of 51 | * execution to another thread (to run the event loop on the original thread, 52 | * in this case). 53 | */ 54 | 55 | class gil_scoped_acquire { 56 | public: 57 | PYBIND11_NOINLINE gil_scoped_acquire() { 58 | auto &internals = detail::get_internals(); 59 | tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); 60 | 61 | if (!tstate) { 62 | /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if 63 | calling from a Python thread). Since we use a different key, this ensures 64 | we don't create a new thread state and deadlock in PyEval_AcquireThread 65 | below. Note we don't save this state with internals.tstate, since we don't 66 | create it we would fail to clear it (its reference count should be > 0). */ 67 | tstate = PyGILState_GetThisThreadState(); 68 | } 69 | 70 | if (!tstate) { 71 | tstate = PyThreadState_New(internals.istate); 72 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) 73 | if (!tstate) { 74 | pybind11_fail("scoped_acquire: could not create thread state!"); 75 | } 76 | # endif 77 | tstate->gilstate_counter = 0; 78 | PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); 79 | } else { 80 | release = detail::get_thread_state_unchecked() != tstate; 81 | } 82 | 83 | if (release) { 84 | PyEval_AcquireThread(tstate); 85 | } 86 | 87 | inc_ref(); 88 | } 89 | 90 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; 91 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; 92 | 93 | void inc_ref() { ++tstate->gilstate_counter; } 94 | 95 | PYBIND11_NOINLINE void dec_ref() { 96 | --tstate->gilstate_counter; 97 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) 98 | if (detail::get_thread_state_unchecked() != tstate) { 99 | pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); 100 | } 101 | if (tstate->gilstate_counter < 0) { 102 | pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); 103 | } 104 | # endif 105 | if (tstate->gilstate_counter == 0) { 106 | # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) 107 | if (!release) { 108 | pybind11_fail("scoped_acquire::dec_ref(): internal error!"); 109 | } 110 | # endif 111 | PyThreadState_Clear(tstate); 112 | if (active) { 113 | PyThreadState_DeleteCurrent(); 114 | } 115 | PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); 116 | release = false; 117 | } 118 | } 119 | 120 | /// This method will disable the PyThreadState_DeleteCurrent call and the 121 | /// GIL won't be acquired. This method should be used if the interpreter 122 | /// could be shutting down when this is called, as thread deletion is not 123 | /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and 124 | /// protect subsequent code. 125 | PYBIND11_NOINLINE void disarm() { active = false; } 126 | 127 | PYBIND11_NOINLINE ~gil_scoped_acquire() { 128 | dec_ref(); 129 | if (release) { 130 | PyEval_SaveThread(); 131 | } 132 | } 133 | 134 | private: 135 | PyThreadState *tstate = nullptr; 136 | bool release = true; 137 | bool active = true; 138 | }; 139 | 140 | class gil_scoped_release { 141 | public: 142 | // PRECONDITION: The GIL must be held when this constructor is called. 143 | explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { 144 | assert(PyGILState_Check()); 145 | // `get_internals()` must be called here unconditionally in order to initialize 146 | // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an 147 | // initialization race could occur as multiple threads try `gil_scoped_acquire`. 148 | auto &internals = detail::get_internals(); 149 | // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) 150 | tstate = PyEval_SaveThread(); 151 | if (disassoc) { 152 | // Python >= 3.7 can remove this, it's an int before 3.7 153 | // NOLINTNEXTLINE(readability-qualified-auto) 154 | auto key = internals.tstate; 155 | PYBIND11_TLS_DELETE_VALUE(key); 156 | } 157 | } 158 | 159 | gil_scoped_release(const gil_scoped_release &) = delete; 160 | gil_scoped_release &operator=(const gil_scoped_release &) = delete; 161 | 162 | /// This method will disable the PyThreadState_DeleteCurrent call and the 163 | /// GIL won't be acquired. This method should be used if the interpreter 164 | /// could be shutting down when this is called, as thread deletion is not 165 | /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and 166 | /// protect subsequent code. 167 | PYBIND11_NOINLINE void disarm() { active = false; } 168 | 169 | ~gil_scoped_release() { 170 | if (!tstate) { 171 | return; 172 | } 173 | // `PyEval_RestoreThread()` should not be called if runtime is finalizing 174 | if (active) { 175 | PyEval_RestoreThread(tstate); 176 | } 177 | if (disassoc) { 178 | // Python >= 3.7 can remove this, it's an int before 3.7 179 | // NOLINTNEXTLINE(readability-qualified-auto) 180 | auto key = detail::get_internals().tstate; 181 | PYBIND11_TLS_REPLACE_VALUE(key, tstate); 182 | } 183 | } 184 | 185 | private: 186 | PyThreadState *tstate; 187 | bool disassoc; 188 | bool active = true; 189 | }; 190 | 191 | # else // PYBIND11_SIMPLE_GIL_MANAGEMENT 192 | 193 | class gil_scoped_acquire { 194 | PyGILState_STATE state; 195 | 196 | public: 197 | gil_scoped_acquire() : state{PyGILState_Ensure()} {} 198 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; 199 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; 200 | ~gil_scoped_acquire() { PyGILState_Release(state); } 201 | void disarm() {} 202 | }; 203 | 204 | class gil_scoped_release { 205 | PyThreadState *state; 206 | 207 | public: 208 | // PRECONDITION: The GIL must be held when this constructor is called. 209 | gil_scoped_release() { 210 | assert(PyGILState_Check()); 211 | state = PyEval_SaveThread(); 212 | } 213 | gil_scoped_release(const gil_scoped_release &) = delete; 214 | gil_scoped_release &operator=(const gil_scoped_release &) = delete; 215 | ~gil_scoped_release() { PyEval_RestoreThread(state); } 216 | void disarm() {} 217 | }; 218 | 219 | # endif // PYBIND11_SIMPLE_GIL_MANAGEMENT 220 | 221 | #else // WITH_THREAD 222 | 223 | class gil_scoped_acquire { 224 | public: 225 | gil_scoped_acquire() { 226 | // Trick to suppress `unused variable` error messages (at call sites). 227 | (void) (this != (this + 1)); 228 | } 229 | gil_scoped_acquire(const gil_scoped_acquire &) = delete; 230 | gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; 231 | void disarm() {} 232 | }; 233 | 234 | class gil_scoped_release { 235 | public: 236 | gil_scoped_release() { 237 | // Trick to suppress `unused variable` error messages (at call sites). 238 | (void) (this != (this + 1)); 239 | } 240 | gil_scoped_release(const gil_scoped_release &) = delete; 241 | gil_scoped_release &operator=(const gil_scoped_release &) = delete; 242 | void disarm() {} 243 | }; 244 | 245 | #endif // WITH_THREAD 246 | 247 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 248 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/gil_safe_call_once.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 The pybind Community. 2 | 3 | #pragma once 4 | 5 | #include "detail/common.h" 6 | #include "gil.h" 7 | 8 | #include 9 | #include 10 | 11 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 12 | 13 | // Use the `gil_safe_call_once_and_store` class below instead of the naive 14 | // 15 | // static auto imported_obj = py::module_::import("module_name"); // BAD, DO NOT USE! 16 | // 17 | // which has two serious issues: 18 | // 19 | // 1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and 20 | // 2. deadlocks in multi-threaded processes (because of missing lock ordering). 21 | // 22 | // The following alternative avoids both problems: 23 | // 24 | // PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store storage; 25 | // auto &imported_obj = storage // Do NOT make this `static`! 26 | // .call_once_and_store_result([]() { 27 | // return py::module_::import("module_name"); 28 | // }) 29 | // .get_stored(); 30 | // 31 | // The parameter of `call_once_and_store_result()` must be callable. It can make 32 | // CPython API calls, and in particular, it can temporarily release the GIL. 33 | // 34 | // `T` can be any C++ type, it does not have to involve CPython API types. 35 | // 36 | // The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`), 37 | // is not ideal. If the main thread is the one to actually run the `Callable`, 38 | // then a `KeyboardInterrupt` will interrupt it if it is running normal Python 39 | // code. The situation is different if a non-main thread runs the 40 | // `Callable`, and then the main thread starts waiting for it to complete: 41 | // a `KeyboardInterrupt` will not interrupt the non-main thread, but it will 42 | // get processed only when it is the main thread's turn again and it is running 43 | // normal Python code. However, this will be unnoticeable for quick call-once 44 | // functions, which is usually the case. 45 | template 46 | class gil_safe_call_once_and_store { 47 | public: 48 | // PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called. 49 | template 50 | gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) { 51 | if (!is_initialized_) { // This read is guarded by the GIL. 52 | // Multiple threads may enter here, because the GIL is released in the next line and 53 | // CPython API calls in the `fn()` call below may release and reacquire the GIL. 54 | gil_scoped_release gil_rel; // Needed to establish lock ordering. 55 | std::call_once(once_flag_, [&] { 56 | // Only one thread will ever enter here. 57 | gil_scoped_acquire gil_acq; 58 | ::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL. 59 | is_initialized_ = true; // This write is guarded by the GIL. 60 | }); 61 | // All threads will observe `is_initialized_` as true here. 62 | } 63 | // Intentionally not returning `T &` to ensure the calling code is self-documenting. 64 | return *this; 65 | } 66 | 67 | // This must only be called after `call_once_and_store_result()` was called. 68 | T &get_stored() { 69 | assert(is_initialized_); 70 | PYBIND11_WARNING_PUSH 71 | #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5 72 | // Needed for gcc 4.8.5 73 | PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing") 74 | #endif 75 | return *reinterpret_cast(storage_); 76 | PYBIND11_WARNING_POP 77 | } 78 | 79 | constexpr gil_safe_call_once_and_store() = default; 80 | PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default; 81 | 82 | private: 83 | alignas(T) char storage_[sizeof(T)] = {}; 84 | std::once_flag once_flag_ = {}; 85 | bool is_initialized_ = false; 86 | // The `is_initialized_`-`storage_` pair is very similar to `std::optional`, 87 | // but the latter does not have the triviality properties of former, 88 | // therefore `std::optional` is not a viable alternative here. 89 | }; 90 | 91 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 92 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/options.h: global settings that are configurable at runtime. 3 | 4 | Copyright (c) 2016 Wenzel Jakob 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "detail/common.h" 13 | 14 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15 | 16 | class options { 17 | public: 18 | // Default RAII constructor, which leaves settings as they currently are. 19 | options() : previous_state(global_state()) {} 20 | 21 | // Class is non-copyable. 22 | options(const options &) = delete; 23 | options &operator=(const options &) = delete; 24 | 25 | // Destructor, which restores settings that were in effect before. 26 | ~options() { global_state() = previous_state; } 27 | 28 | // Setter methods (affect the global state): 29 | 30 | options &disable_user_defined_docstrings() & { 31 | global_state().show_user_defined_docstrings = false; 32 | return *this; 33 | } 34 | 35 | options &enable_user_defined_docstrings() & { 36 | global_state().show_user_defined_docstrings = true; 37 | return *this; 38 | } 39 | 40 | options &disable_function_signatures() & { 41 | global_state().show_function_signatures = false; 42 | return *this; 43 | } 44 | 45 | options &enable_function_signatures() & { 46 | global_state().show_function_signatures = true; 47 | return *this; 48 | } 49 | 50 | options &disable_enum_members_docstring() & { 51 | global_state().show_enum_members_docstring = false; 52 | return *this; 53 | } 54 | 55 | options &enable_enum_members_docstring() & { 56 | global_state().show_enum_members_docstring = true; 57 | return *this; 58 | } 59 | 60 | // Getter methods (return the global state): 61 | 62 | static bool show_user_defined_docstrings() { 63 | return global_state().show_user_defined_docstrings; 64 | } 65 | 66 | static bool show_function_signatures() { return global_state().show_function_signatures; } 67 | 68 | static bool show_enum_members_docstring() { 69 | return global_state().show_enum_members_docstring; 70 | } 71 | 72 | // This type is not meant to be allocated on the heap. 73 | void *operator new(size_t) = delete; 74 | 75 | private: 76 | struct state { 77 | bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. 78 | bool show_function_signatures = true; //< Include auto-generated function signatures 79 | // in docstrings. 80 | bool show_enum_members_docstring = true; //< Include auto-generated member list in enum 81 | // docstrings. 82 | }; 83 | 84 | static state &global_state() { 85 | static state instance; 86 | return instance; 87 | } 88 | 89 | state previous_state; 90 | }; 91 | 92 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 93 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/stl/filesystem.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 The Pybind Development Team. 2 | // All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | #pragma once 6 | 7 | #include "../pybind11.h" 8 | #include "../detail/common.h" 9 | #include "../detail/descr.h" 10 | #include "../cast.h" 11 | #include "../pytypes.h" 12 | 13 | #include 14 | 15 | #ifdef __has_include 16 | # if defined(PYBIND11_CPP17) 17 | # if __has_include() && \ 18 | PY_VERSION_HEX >= 0x03060000 19 | # include 20 | # define PYBIND11_HAS_FILESYSTEM 1 21 | # elif __has_include() 22 | # include 23 | # define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1 24 | # endif 25 | # endif 26 | #endif 27 | 28 | #if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \ 29 | && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) 30 | # error \ 31 | "Neither #include nor #include 39 | struct path_caster { 40 | 41 | private: 42 | static PyObject *unicode_from_fs_native(const std::string &w) { 43 | # if !defined(PYPY_VERSION) 44 | return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size())); 45 | # else 46 | // PyPy mistakenly declares the first parameter as non-const. 47 | return PyUnicode_DecodeFSDefaultAndSize(const_cast(w.c_str()), ssize_t(w.size())); 48 | # endif 49 | } 50 | 51 | static PyObject *unicode_from_fs_native(const std::wstring &w) { 52 | return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size())); 53 | } 54 | 55 | public: 56 | static handle cast(const T &path, return_value_policy, handle) { 57 | if (auto py_str = unicode_from_fs_native(path.native())) { 58 | return module_::import("pathlib") 59 | .attr("Path")(reinterpret_steal(py_str)) 60 | .release(); 61 | } 62 | return nullptr; 63 | } 64 | 65 | bool load(handle handle, bool) { 66 | // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of 67 | // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy 68 | // issue #3168) so we do it ourselves instead. 69 | PyObject *buf = PyOS_FSPath(handle.ptr()); 70 | if (!buf) { 71 | PyErr_Clear(); 72 | return false; 73 | } 74 | PyObject *native = nullptr; 75 | if constexpr (std::is_same_v) { 76 | if (PyUnicode_FSConverter(buf, &native) != 0) { 77 | if (auto *c_str = PyBytes_AsString(native)) { 78 | // AsString returns a pointer to the internal buffer, which 79 | // must not be free'd. 80 | value = c_str; 81 | } 82 | } 83 | } else if constexpr (std::is_same_v) { 84 | if (PyUnicode_FSDecoder(buf, &native) != 0) { 85 | if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) { 86 | // AsWideCharString returns a new string that must be free'd. 87 | value = c_str; // Copies the string. 88 | PyMem_Free(c_str); 89 | } 90 | } 91 | } 92 | Py_XDECREF(native); 93 | Py_DECREF(buf); 94 | if (PyErr_Occurred()) { 95 | PyErr_Clear(); 96 | return false; 97 | } 98 | return true; 99 | } 100 | 101 | PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); 102 | }; 103 | 104 | #endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) 105 | 106 | #if defined(PYBIND11_HAS_FILESYSTEM) 107 | template <> 108 | struct type_caster : public path_caster {}; 109 | #elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) 110 | template <> 111 | struct type_caster 112 | : public path_caster {}; 113 | #endif 114 | 115 | PYBIND11_NAMESPACE_END(detail) 116 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 117 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/type_caster_pyobject_ptr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 The pybind Community. 2 | 3 | #pragma once 4 | 5 | #include "detail/common.h" 6 | #include "detail/descr.h" 7 | #include "cast.h" 8 | #include "pytypes.h" 9 | 10 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 11 | PYBIND11_NAMESPACE_BEGIN(detail) 12 | 13 | template <> 14 | class type_caster { 15 | public: 16 | static constexpr auto name = const_name("object"); // See discussion under PR #4601. 17 | 18 | // This overload is purely to guard against accidents. 19 | template ::value, int> = 0> 21 | static handle cast(T &&, return_value_policy, handle /*parent*/) { 22 | static_assert(is_same_ignoring_cvref::value, 23 | "Invalid C++ type T for to-Python conversion (type_caster)."); 24 | return nullptr; // Unreachable. 25 | } 26 | 27 | static handle cast(PyObject *src, return_value_policy policy, handle /*parent*/) { 28 | if (src == nullptr) { 29 | throw error_already_set(); 30 | } 31 | if (PyErr_Occurred()) { 32 | raise_from(PyExc_SystemError, "src != nullptr but PyErr_Occurred()"); 33 | throw error_already_set(); 34 | } 35 | if (policy == return_value_policy::take_ownership) { 36 | return src; 37 | } 38 | if (policy == return_value_policy::reference 39 | || policy == return_value_policy::automatic_reference) { 40 | return handle(src).inc_ref(); 41 | } 42 | pybind11_fail("type_caster::cast(): unsupported return_value_policy: " 43 | + std::to_string(static_cast(policy))); 44 | } 45 | 46 | bool load(handle src, bool) { 47 | value = reinterpret_borrow(src); 48 | return true; 49 | } 50 | 51 | template 52 | using cast_op_type = PyObject *; 53 | 54 | explicit operator PyObject *() { return value.ptr(); } 55 | 56 | private: 57 | object value; 58 | }; 59 | 60 | PYBIND11_NAMESPACE_END(detail) 61 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 62 | -------------------------------------------------------------------------------- /source/third_party/pybind11/include/pybind11/typing.h: -------------------------------------------------------------------------------- 1 | /* 2 | pybind11/typing.h: Convenience wrapper classes for basic Python types 3 | with more explicit annotations. 4 | 5 | Copyright (c) 2023 Dustin Spicuzza 6 | 7 | All rights reserved. Use of this source code is governed by a 8 | BSD-style license that can be found in the LICENSE file. 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "detail/common.h" 14 | #include "cast.h" 15 | #include "pytypes.h" 16 | 17 | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 18 | PYBIND11_NAMESPACE_BEGIN(typing) 19 | 20 | /* 21 | The following types can be used to direct pybind11-generated docstrings 22 | to have have more explicit types (e.g., `list[str]` instead of `list`). 23 | Just use these in place of existing types. 24 | 25 | There is no additional enforcement of types at runtime. 26 | */ 27 | 28 | template 29 | class Tuple : public tuple { 30 | using tuple::tuple; 31 | }; 32 | 33 | template 34 | class Dict : public dict { 35 | using dict::dict; 36 | }; 37 | 38 | template 39 | class List : public list { 40 | using list::list; 41 | }; 42 | 43 | template 44 | class Set : public set { 45 | using set::set; 46 | }; 47 | 48 | template 49 | class Iterable : public iterable { 50 | using iterable::iterable; 51 | }; 52 | 53 | template 54 | class Iterator : public iterator { 55 | using iterator::iterator; 56 | }; 57 | 58 | template 59 | class Callable; 60 | 61 | template 62 | class Callable : public function { 63 | using function::function; 64 | }; 65 | 66 | PYBIND11_NAMESPACE_END(typing) 67 | 68 | PYBIND11_NAMESPACE_BEGIN(detail) 69 | 70 | template 71 | struct handle_type_name> { 72 | static constexpr auto name = const_name("tuple[") 73 | + ::pybind11::detail::concat(make_caster::name...) 74 | + const_name("]"); 75 | }; 76 | 77 | template <> 78 | struct handle_type_name> { 79 | // PEP 484 specifies this syntax for an empty tuple 80 | static constexpr auto name = const_name("tuple[()]"); 81 | }; 82 | 83 | template 84 | struct handle_type_name> { 85 | // PEP 484 specifies this syntax for a variable-length tuple 86 | static constexpr auto name 87 | = const_name("tuple[") + make_caster::name + const_name(", ...]"); 88 | }; 89 | 90 | template 91 | struct handle_type_name> { 92 | static constexpr auto name = const_name("dict[") + make_caster::name + const_name(", ") 93 | + make_caster::name + const_name("]"); 94 | }; 95 | 96 | template 97 | struct handle_type_name> { 98 | static constexpr auto name = const_name("list[") + make_caster::name + const_name("]"); 99 | }; 100 | 101 | template 102 | struct handle_type_name> { 103 | static constexpr auto name = const_name("set[") + make_caster::name + const_name("]"); 104 | }; 105 | 106 | template 107 | struct handle_type_name> { 108 | static constexpr auto name = const_name("Iterable[") + make_caster::name + const_name("]"); 109 | }; 110 | 111 | template 112 | struct handle_type_name> { 113 | static constexpr auto name = const_name("Iterator[") + make_caster::name + const_name("]"); 114 | }; 115 | 116 | template 117 | struct handle_type_name> { 118 | using retval_type = conditional_t::value, void_type, Return>; 119 | static constexpr auto name 120 | = const_name("Callable[[") + ::pybind11::detail::concat(make_caster::name...) 121 | + const_name("], ") + make_caster::name + const_name("]"); 122 | }; 123 | 124 | PYBIND11_NAMESPACE_END(detail) 125 | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) 126 | -------------------------------------------------------------------------------- /source/third_party/pybind11/pybind11/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.version_info < (3, 6): # noqa: UP036 4 | msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." 5 | raise ImportError(msg) 6 | 7 | 8 | from ._version import __version__, version_info 9 | from .commands import get_cmake_dir, get_include, get_pkgconfig_dir 10 | 11 | __all__ = ( 12 | "version_info", 13 | "__version__", 14 | "get_include", 15 | "get_cmake_dir", 16 | "get_pkgconfig_dir", 17 | ) 18 | -------------------------------------------------------------------------------- /source/third_party/pybind11/pybind11/__main__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-function-docstring 2 | 3 | import argparse 4 | import sys 5 | import sysconfig 6 | 7 | from ._version import __version__ 8 | from .commands import get_cmake_dir, get_include, get_pkgconfig_dir 9 | 10 | 11 | def print_includes() -> None: 12 | dirs = [ 13 | sysconfig.get_path("include"), 14 | sysconfig.get_path("platinclude"), 15 | get_include(), 16 | ] 17 | 18 | # Make unique but preserve order 19 | unique_dirs = [] 20 | for d in dirs: 21 | if d and d not in unique_dirs: 22 | unique_dirs.append(d) 23 | 24 | print(" ".join("-I" + d for d in unique_dirs)) 25 | 26 | 27 | def main() -> None: 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument( 30 | "--version", 31 | action="version", 32 | version=__version__, 33 | help="Print the version and exit.", 34 | ) 35 | parser.add_argument( 36 | "--includes", 37 | action="store_true", 38 | help="Include flags for both pybind11 and Python headers.", 39 | ) 40 | parser.add_argument( 41 | "--cmakedir", 42 | action="store_true", 43 | help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.", 44 | ) 45 | parser.add_argument( 46 | "--pkgconfigdir", 47 | action="store_true", 48 | help="Print the pkgconfig directory, ideal for setting $PKG_CONFIG_PATH.", 49 | ) 50 | args = parser.parse_args() 51 | if not sys.argv[1:]: 52 | parser.print_help() 53 | if args.includes: 54 | print_includes() 55 | if args.cmakedir: 56 | print(get_cmake_dir()) 57 | if args.pkgconfigdir: 58 | print(get_pkgconfig_dir()) 59 | 60 | 61 | if __name__ == "__main__": 62 | main() 63 | -------------------------------------------------------------------------------- /source/third_party/pybind11/pybind11/_version.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | 4 | def _to_int(s: str) -> Union[int, str]: 5 | try: 6 | return int(s) 7 | except ValueError: 8 | return s 9 | 10 | 11 | __version__ = "2.13.0.dev1" 12 | version_info = tuple(_to_int(s) for s in __version__.split(".")) 13 | -------------------------------------------------------------------------------- /source/third_party/pybind11/pybind11/commands.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | DIR = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | 6 | def get_include(user: bool = False) -> str: # noqa: ARG001 7 | """ 8 | Return the path to the pybind11 include directory. The historical "user" 9 | argument is unused, and may be removed. 10 | """ 11 | installed_path = os.path.join(DIR, "include") 12 | source_path = os.path.join(os.path.dirname(DIR), "include") 13 | return installed_path if os.path.exists(installed_path) else source_path 14 | 15 | 16 | def get_cmake_dir() -> str: 17 | """ 18 | Return the path to the pybind11 CMake module directory. 19 | """ 20 | cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11") 21 | if os.path.exists(cmake_installed_path): 22 | return cmake_installed_path 23 | 24 | msg = "pybind11 not installed, installation required to access the CMake files" 25 | raise ImportError(msg) 26 | 27 | 28 | def get_pkgconfig_dir() -> str: 29 | """ 30 | Return the path to the pybind11 pkgconfig directory. 31 | """ 32 | pkgconfig_installed_path = os.path.join(DIR, "share", "pkgconfig") 33 | if os.path.exists(pkgconfig_installed_path): 34 | return pkgconfig_installed_path 35 | 36 | msg = "pybind11 not installed, installation required to access the pkgconfig files" 37 | raise ImportError(msg) 38 | -------------------------------------------------------------------------------- /source/third_party/pybind11/pybind11/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jianxff/pysrt3d/aa587362a1da37040cb2e38371936af9e4f37af7/source/third_party/pybind11/pybind11/py.typed -------------------------------------------------------------------------------- /source/third_party/pybind11/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | long_description = file: README.rst 3 | long_description_content_type = text/x-rst 4 | description = Seamless operability between C++11 and Python 5 | author = Wenzel Jakob 6 | author_email = wenzel.jakob@epfl.ch 7 | url = https://github.com/pybind/pybind11 8 | license = BSD 9 | 10 | classifiers = 11 | Development Status :: 5 - Production/Stable 12 | Intended Audience :: Developers 13 | Topic :: Software Development :: Libraries :: Python Modules 14 | Topic :: Utilities 15 | Programming Language :: C++ 16 | Programming Language :: Python :: 3 :: Only 17 | Programming Language :: Python :: 3.6 18 | Programming Language :: Python :: 3.7 19 | Programming Language :: Python :: 3.8 20 | Programming Language :: Python :: 3.9 21 | Programming Language :: Python :: 3.10 22 | Programming Language :: Python :: 3.11 23 | Programming Language :: Python :: 3.12 24 | License :: OSI Approved :: BSD License 25 | Programming Language :: Python :: Implementation :: PyPy 26 | Programming Language :: Python :: Implementation :: CPython 27 | Programming Language :: C++ 28 | Topic :: Software Development :: Libraries :: Python Modules 29 | 30 | keywords = 31 | C++11 32 | Python bindings 33 | 34 | project_urls = 35 | Documentation = https://pybind11.readthedocs.io/ 36 | Bug Tracker = https://github.com/pybind/pybind11/issues 37 | Discussions = https://github.com/pybind/pybind11/discussions 38 | Changelog = https://pybind11.readthedocs.io/en/latest/changelog.html 39 | Chat = https://gitter.im/pybind/Lobby 40 | 41 | [options] 42 | python_requires = >=3.6 43 | zip_safe = False 44 | -------------------------------------------------------------------------------- /source/third_party/pybind11/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Setup script for PyPI; use CMakeFile.txt to build extension modules 4 | 5 | import contextlib 6 | import os 7 | import re 8 | import shutil 9 | import string 10 | import subprocess 11 | import sys 12 | from pathlib import Path 13 | from tempfile import TemporaryDirectory 14 | from typing import Dict, Iterator, List, Union 15 | 16 | import setuptools.command.sdist 17 | 18 | DIR = Path(__file__).parent.absolute() 19 | VERSION_REGEX = re.compile( 20 | r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE 21 | ) 22 | VERSION_FILE = Path("pybind11/_version.py") 23 | COMMON_FILE = Path("include/pybind11/detail/common.h") 24 | 25 | 26 | def build_expected_version_hex(matches: Dict[str, str]) -> str: 27 | patch_level_serial = matches["PATCH"] 28 | serial = None 29 | major = int(matches["MAJOR"]) 30 | minor = int(matches["MINOR"]) 31 | flds = patch_level_serial.split(".") 32 | if flds: 33 | patch = int(flds[0]) 34 | if len(flds) == 1: 35 | level = "0" 36 | serial = 0 37 | elif len(flds) == 2: 38 | level_serial = flds[1] 39 | for level in ("a", "b", "c", "dev"): 40 | if level_serial.startswith(level): 41 | serial = int(level_serial[len(level) :]) 42 | break 43 | if serial is None: 44 | msg = f'Invalid PYBIND11_VERSION_PATCH: "{patch_level_serial}"' 45 | raise RuntimeError(msg) 46 | version_hex_str = f"{major:02x}{minor:02x}{patch:02x}{level[:1]}{serial:x}" 47 | return f"0x{version_hex_str.upper()}" 48 | 49 | 50 | # PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers 51 | # files, and the sys.prefix files (CMake and headers). 52 | 53 | global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False) 54 | 55 | setup_py = Path( 56 | "tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in" 57 | ) 58 | extra_cmd = 'cmdclass["sdist"] = SDist\n' 59 | 60 | to_src = ( 61 | (Path("pyproject.toml"), Path("tools/pyproject.toml")), 62 | (Path("setup.py"), setup_py), 63 | ) 64 | 65 | 66 | # Read the listed version 67 | loc: Dict[str, str] = {} 68 | code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec") 69 | exec(code, loc) 70 | version = loc["__version__"] 71 | 72 | # Verify that the version matches the one in C++ 73 | matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8"))) 74 | cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches) 75 | if version != cpp_version: 76 | msg = f"Python version {version} does not match C++ version {cpp_version}!" 77 | raise RuntimeError(msg) 78 | 79 | version_hex = matches.get("HEX", "MISSING") 80 | exp_version_hex = build_expected_version_hex(matches) 81 | if version_hex != exp_version_hex: 82 | msg = f"PYBIND11_VERSION_HEX {version_hex} does not match expected value {exp_version_hex}!" 83 | raise RuntimeError(msg) 84 | 85 | 86 | # TODO: use literals & overload (typing extensions or Python 3.8) 87 | def get_and_replace( 88 | filename: Path, binary: bool = False, **opts: str 89 | ) -> Union[bytes, str]: 90 | if binary: 91 | contents = filename.read_bytes() 92 | return string.Template(contents.decode()).substitute(opts).encode() 93 | 94 | return string.Template(filename.read_text()).substitute(opts) 95 | 96 | 97 | # Use our input files instead when making the SDist (and anything that depends 98 | # on it, like a wheel) 99 | class SDist(setuptools.command.sdist.sdist): 100 | def make_release_tree(self, base_dir: str, files: List[str]) -> None: 101 | super().make_release_tree(base_dir, files) 102 | 103 | for to, src in to_src: 104 | txt = get_and_replace(src, binary=True, version=version, extra_cmd="") 105 | 106 | dest = Path(base_dir) / to 107 | 108 | # This is normally linked, so unlink before writing! 109 | dest.unlink() 110 | dest.write_bytes(txt) # type: ignore[arg-type] 111 | 112 | 113 | # Remove the CMake install directory when done 114 | @contextlib.contextmanager 115 | def remove_output(*sources: str) -> Iterator[None]: 116 | try: 117 | yield 118 | finally: 119 | for src in sources: 120 | shutil.rmtree(src) 121 | 122 | 123 | with remove_output("pybind11/include", "pybind11/share"): 124 | # Generate the files if they are not present. 125 | with TemporaryDirectory() as tmpdir: 126 | cmd = ["cmake", "-S", ".", "-B", tmpdir] + [ 127 | "-DCMAKE_INSTALL_PREFIX=pybind11", 128 | "-DBUILD_TESTING=OFF", 129 | "-DPYBIND11_NOPYTHON=ON", 130 | "-Dprefix_for_pc_file=${pcfiledir}/../../", 131 | ] 132 | if "CMAKE_ARGS" in os.environ: 133 | fcommand = [ 134 | c 135 | for c in os.environ["CMAKE_ARGS"].split() 136 | if "DCMAKE_INSTALL_PREFIX" not in c 137 | ] 138 | cmd += fcommand 139 | subprocess.run(cmd, check=True, cwd=DIR, stdout=sys.stdout, stderr=sys.stderr) 140 | subprocess.run( 141 | ["cmake", "--install", tmpdir], 142 | check=True, 143 | cwd=DIR, 144 | stdout=sys.stdout, 145 | stderr=sys.stderr, 146 | ) 147 | 148 | txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd) 149 | code = compile(txt, setup_py, "exec") 150 | exec(code, {"SDist": SDist}) 151 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/FindCatch.cmake: -------------------------------------------------------------------------------- 1 | # - Find the Catch test framework or download it (single header) 2 | # 3 | # This is a quick module for internal use. It assumes that Catch is 4 | # REQUIRED and that a minimum version is provided (not EXACT). If 5 | # a suitable version isn't found locally, the single header file 6 | # will be downloaded and placed in the build dir: PROJECT_BINARY_DIR. 7 | # 8 | # This code sets the following variables: 9 | # CATCH_INCLUDE_DIR - path to catch.hpp 10 | # CATCH_VERSION - version number 11 | 12 | option(DOWNLOAD_CATCH "Download catch2 if not found") 13 | 14 | if(NOT Catch_FIND_VERSION) 15 | message(FATAL_ERROR "A version number must be specified.") 16 | elseif(Catch_FIND_REQUIRED) 17 | message(FATAL_ERROR "This module assumes Catch is not required.") 18 | elseif(Catch_FIND_VERSION_EXACT) 19 | message(FATAL_ERROR "Exact version numbers are not supported, only minimum.") 20 | endif() 21 | 22 | # Extract the version number from catch.hpp 23 | function(_get_catch_version) 24 | file( 25 | STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line 26 | REGEX "Catch v.*" 27 | LIMIT_COUNT 1) 28 | if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)") 29 | set(CATCH_VERSION 30 | "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" 31 | PARENT_SCOPE) 32 | endif() 33 | endfunction() 34 | 35 | # Download the single-header version of Catch 36 | function(_download_catch version destination_dir) 37 | message(STATUS "Downloading catch v${version}...") 38 | set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) 39 | file( 40 | DOWNLOAD ${url} "${destination_dir}/catch.hpp" 41 | STATUS status 42 | LOG log) 43 | list(GET status 0 error) 44 | if(error) 45 | string(REPLACE "\n" "\n " log " ${log}") 46 | message(FATAL_ERROR "Could not download URL:\n" " ${url}\n" "Log:\n" "${log}") 47 | endif() 48 | set(CATCH_INCLUDE_DIR 49 | "${destination_dir}" 50 | CACHE INTERNAL "") 51 | endfunction() 52 | 53 | # Look for catch locally 54 | find_path( 55 | CATCH_INCLUDE_DIR 56 | NAMES catch.hpp 57 | PATH_SUFFIXES catch2) 58 | if(CATCH_INCLUDE_DIR) 59 | _get_catch_version() 60 | endif() 61 | 62 | # Download the header if it wasn't found or if it's outdated 63 | if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) 64 | if(DOWNLOAD_CATCH) 65 | _download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/") 66 | _get_catch_version() 67 | else() 68 | set(CATCH_FOUND FALSE) 69 | return() 70 | endif() 71 | endif() 72 | 73 | add_library(Catch2::Catch2 IMPORTED INTERFACE) 74 | set_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}") 75 | 76 | set(CATCH_FOUND TRUE) 77 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/FindEigen3.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Eigen3 lib 2 | # 3 | # This module supports requiring a minimum version, e.g. you can do 4 | # find_package(Eigen3 3.1.2) 5 | # to require version 3.1.2 or newer of Eigen3. 6 | # 7 | # Once done this will define 8 | # 9 | # EIGEN3_FOUND - system has eigen lib with correct version 10 | # EIGEN3_INCLUDE_DIR - the eigen include directory 11 | # EIGEN3_VERSION - eigen version 12 | 13 | # Copyright (c) 2006, 2007 Montel Laurent, 14 | # Copyright (c) 2008, 2009 Gael Guennebaud, 15 | # Copyright (c) 2009 Benoit Jacob 16 | # Redistribution and use is allowed according to the terms of the 2-clause BSD license. 17 | 18 | if(NOT Eigen3_FIND_VERSION) 19 | if(NOT Eigen3_FIND_VERSION_MAJOR) 20 | set(Eigen3_FIND_VERSION_MAJOR 2) 21 | endif(NOT Eigen3_FIND_VERSION_MAJOR) 22 | if(NOT Eigen3_FIND_VERSION_MINOR) 23 | set(Eigen3_FIND_VERSION_MINOR 91) 24 | endif(NOT Eigen3_FIND_VERSION_MINOR) 25 | if(NOT Eigen3_FIND_VERSION_PATCH) 26 | set(Eigen3_FIND_VERSION_PATCH 0) 27 | endif(NOT Eigen3_FIND_VERSION_PATCH) 28 | 29 | set(Eigen3_FIND_VERSION 30 | "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") 31 | endif(NOT Eigen3_FIND_VERSION) 32 | 33 | macro(_eigen3_check_version) 34 | file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) 35 | 36 | string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match 37 | "${_eigen3_version_header}") 38 | set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") 39 | string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match 40 | "${_eigen3_version_header}") 41 | set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") 42 | string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match 43 | "${_eigen3_version_header}") 44 | set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") 45 | 46 | set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) 47 | if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 48 | set(EIGEN3_VERSION_OK FALSE) 49 | else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 50 | set(EIGEN3_VERSION_OK TRUE) 51 | endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 52 | 53 | if(NOT EIGEN3_VERSION_OK) 54 | 55 | message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " 56 | "but at least version ${Eigen3_FIND_VERSION} is required") 57 | endif(NOT EIGEN3_VERSION_OK) 58 | endmacro(_eigen3_check_version) 59 | 60 | if(EIGEN3_INCLUDE_DIR) 61 | 62 | # in cache already 63 | _eigen3_check_version() 64 | set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) 65 | 66 | else(EIGEN3_INCLUDE_DIR) 67 | if(NOT DEFINED KDE4_INCLUDE_DIR) 68 | set(KDE4_INCLUDE_DIR "") 69 | endif() 70 | 71 | find_path( 72 | EIGEN3_INCLUDE_DIR 73 | NAMES signature_of_eigen3_matrix_library 74 | PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR} 75 | PATH_SUFFIXES eigen3 eigen) 76 | 77 | if(EIGEN3_INCLUDE_DIR) 78 | _eigen3_check_version() 79 | endif(EIGEN3_INCLUDE_DIR) 80 | 81 | include(FindPackageHandleStandardArgs) 82 | find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) 83 | 84 | mark_as_advanced(EIGEN3_INCLUDE_DIR) 85 | 86 | endif(EIGEN3_INCLUDE_DIR) 87 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/JoinPaths.cmake: -------------------------------------------------------------------------------- 1 | # This module provides function for joining paths 2 | # known from most languages 3 | # 4 | # SPDX-License-Identifier: (MIT OR CC0-1.0) 5 | # Copyright 2020 Jan Tojnar 6 | # https://github.com/jtojnar/cmake-snips 7 | # 8 | # Modelled after Python’s os.path.join 9 | # https://docs.python.org/3.7/library/os.path.html#os.path.join 10 | # Windows not supported 11 | function(join_paths joined_path first_path_segment) 12 | set(temp_path "${first_path_segment}") 13 | foreach(current_segment IN LISTS ARGN) 14 | if(NOT ("${current_segment}" STREQUAL "")) 15 | if(IS_ABSOLUTE "${current_segment}") 16 | set(temp_path "${current_segment}") 17 | else() 18 | set(temp_path "${temp_path}/${current_segment}") 19 | endif() 20 | endif() 21 | endforeach() 22 | set(${joined_path} "${temp_path}" PARENT_SCOPE) 23 | endfunction() 24 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/check-style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to check include/test code for common pybind11 code style errors. 4 | # 5 | # This script currently checks for 6 | # 7 | # 1. missing space between keyword and parenthesis, e.g.: for(, if(, while( 8 | # 2. Missing space between right parenthesis and brace, e.g. 'for (...){' 9 | # 3. opening brace on its own line. It should always be on the same line as the 10 | # if/while/for/do statement. 11 | # 12 | # Invoke as: tools/check-style.sh 13 | # 14 | 15 | check_style_errors=0 16 | IFS=$'\n' 17 | 18 | 19 | found="$(grep '\<\(if\|for\|while\|catch\)(\|){' "$@" -rn --color=always)" 20 | if [ -n "$found" ]; then 21 | echo -e '\033[31;01mError: found the following coding style problems:\033[0m' 22 | check_style_errors=1 23 | echo "${found//^/ /}" 24 | fi 25 | 26 | found="$(awk ' 27 | function prefix(filename, lineno) { 28 | return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m" 29 | } 30 | function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string } 31 | last && /^\s*{/ { 32 | print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last) 33 | print prefix(FILENAME, FNR) mark("^\\s*{", $0) 34 | last="" 35 | } 36 | { last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" } 37 | ' "$(find include -type f)" "$@")" 38 | if [ -n "$found" ]; then 39 | check_style_errors=1 40 | echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m' 41 | echo "$found" 42 | fi 43 | 44 | exit $check_style_errors 45 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake 2 | 3 | if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") 4 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") 5 | endif() 6 | 7 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) 8 | string(REGEX REPLACE "\n" ";" files "${files}") 9 | foreach(file ${files}) 10 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 11 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 12 | exec_program( 13 | "@CMAKE_COMMAND@" ARGS 14 | "-E remove \"$ENV{DESTDIR}${file}\"" 15 | OUTPUT_VARIABLE rm_out 16 | RETURN_VALUE rm_retval) 17 | if(NOT "${rm_retval}" STREQUAL 0) 18 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 19 | endif() 20 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 22 | endif() 23 | endforeach() 24 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/codespell_ignore_lines_from_errors.py: -------------------------------------------------------------------------------- 1 | """Simple script for rebuilding .codespell-ignore-lines 2 | 3 | Usage: 4 | 5 | cat < /dev/null > .codespell-ignore-lines 6 | pre-commit run --all-files codespell >& /tmp/codespell_errors.txt 7 | python3 tools/codespell_ignore_lines_from_errors.py /tmp/codespell_errors.txt > .codespell-ignore-lines 8 | 9 | git diff to review changes, then commit, push. 10 | """ 11 | 12 | import sys 13 | from typing import List 14 | 15 | 16 | def run(args: List[str]) -> None: 17 | assert len(args) == 1, "codespell_errors.txt" 18 | cache = {} 19 | done = set() 20 | with open(args[0]) as f: 21 | lines = f.read().splitlines() 22 | 23 | for line in sorted(lines): 24 | i = line.find(" ==> ") 25 | if i > 0: 26 | flds = line[:i].split(":") 27 | if len(flds) >= 2: 28 | filename, line_num = flds[:2] 29 | if filename not in cache: 30 | with open(filename) as f: 31 | cache[filename] = f.read().splitlines() 32 | supp = cache[filename][int(line_num) - 1] 33 | if supp not in done: 34 | print(supp) 35 | done.add(supp) 36 | 37 | 38 | if __name__ == "__main__": 39 | run(args=sys.argv[1:]) 40 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/libsize.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # Internal build script for generating debugging test .so size. 5 | # Usage: 6 | # python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the 7 | # size in it, then overwrites save.txt with the new size for future runs. 8 | 9 | if len(sys.argv) != 3: 10 | sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt") 11 | 12 | lib = sys.argv[1] 13 | save = sys.argv[2] 14 | 15 | if not os.path.exists(lib): 16 | sys.exit(f"Error: requested file ({lib}) does not exist") 17 | 18 | libsize = os.path.getsize(lib) 19 | 20 | print("------", os.path.basename(lib), "file size:", libsize, end="") 21 | 22 | if os.path.exists(save): 23 | with open(save) as sf: 24 | oldsize = int(sf.readline()) 25 | 26 | if oldsize > 0: 27 | change = libsize - oldsize 28 | if change == 0: 29 | print(" (no change)") 30 | else: 31 | print(f" (change of {change:+} bytes = {change / oldsize:+.2%})") 32 | else: 33 | print() 34 | 35 | with open(save, "w") as sf: 36 | sf.write(str(libsize)) 37 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/make_changelog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from __future__ import annotations 3 | 4 | import re 5 | 6 | import ghapi.all 7 | from rich import print 8 | from rich.syntax import Syntax 9 | 10 | ENTRY = re.compile( 11 | r""" 12 | Suggested \s changelog \s entry: 13 | .* 14 | ```rst 15 | \s* 16 | (.*?) 17 | \s* 18 | ``` 19 | """, 20 | re.DOTALL | re.VERBOSE, 21 | ) 22 | 23 | print() 24 | 25 | 26 | api = ghapi.all.GhApi(owner="pybind", repo="pybind11") 27 | 28 | issues_pages = ghapi.page.paged( 29 | api.issues.list_for_repo, labels="needs changelog", state="closed" 30 | ) 31 | issues = (issue for page in issues_pages for issue in page) 32 | missing = [] 33 | cats_descr = { 34 | "feat": "New Features", 35 | "fix": "Bug fixes", 36 | "fix(types)": "", 37 | "fix(cmake)": "", 38 | "docs": "Documentation", 39 | "tests": "Tests", 40 | "ci": "CI", 41 | "chore": "Other", 42 | "unknown": "Uncategorised", 43 | } 44 | cats: dict[str, list[str]] = {c: [] for c in cats_descr} 45 | 46 | for issue in issues: 47 | changelog = ENTRY.findall(issue.body or "") 48 | if not changelog or not changelog[0]: 49 | missing.append(issue) 50 | else: 51 | (msg,) = changelog 52 | if msg.startswith("- "): 53 | msg = msg[2:] 54 | if not msg.startswith("* "): 55 | msg = "* " + msg 56 | if not msg.endswith("."): 57 | msg += "." 58 | 59 | msg += f"\n `#{issue.number} <{issue.html_url}>`_" 60 | for cat in cats: 61 | if issue.title.lower().startswith(f"{cat}:"): 62 | cats[cat].append(msg) 63 | break 64 | else: 65 | cats["unknown"].append(msg) 66 | 67 | for cat, msgs in cats.items(): 68 | if msgs: 69 | desc = cats_descr[cat] 70 | print(f"[bold]{desc}:" if desc else f".. {cat}") 71 | print() 72 | for msg in msgs: 73 | print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True)) 74 | print() 75 | print() 76 | 77 | if missing: 78 | print() 79 | print("[blue]" + "-" * 30) 80 | print() 81 | 82 | for issue in missing: 83 | print(f"[red bold]Missing:[/red bold][red] {issue.title}") 84 | print(f"[red] {issue.html_url}\n") 85 | 86 | print("[bold]Template:\n") 87 | msg = "## Suggested changelog entry:\n\n```rst\n\n```" 88 | print(Syntax(msg, "md", theme="ansi_light")) 89 | 90 | print() 91 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/pybind11.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix_for_pc_file@ 2 | includedir=@includedir_for_pc_file@ 3 | 4 | Name: @PROJECT_NAME@ 5 | Description: Seamless operability between C++11 and Python 6 | Version: @PROJECT_VERSION@ 7 | Cflags: -I${includedir} 8 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/pybind11Config.cmake.in: -------------------------------------------------------------------------------- 1 | #[=============================================================================[.rst: 2 | 3 | pybind11Config.cmake 4 | #################### 5 | 6 | Exported variables 7 | ================== 8 | 9 | This module sets the following variables in your project: 10 | 11 | ``pybind11_FOUND`` 12 | true if pybind11 and all required components found on the system 13 | ``pybind11_VERSION`` 14 | pybind11 version in format Major.Minor.Release 15 | ``pybind11_VERSION_TYPE`` 16 | pybind11 version type (``dev*`` or empty for a release) 17 | ``pybind11_INCLUDE_DIRS`` 18 | Directories where pybind11 and python headers are located. 19 | ``pybind11_INCLUDE_DIR`` 20 | Directory where pybind11 headers are located. 21 | ``pybind11_DEFINITIONS`` 22 | Definitions necessary to use pybind11, namely USING_pybind11. 23 | ``pybind11_LIBRARIES`` 24 | Compile flags and python libraries (as needed) to link against. 25 | ``pybind11_LIBRARY`` 26 | Empty. 27 | 28 | Available components: None 29 | 30 | 31 | Exported targets 32 | ================ 33 | 34 | If pybind11 is found, this module defines the following ``IMPORTED`` 35 | interface library targets: 36 | 37 | ``pybind11::module`` 38 | for extension modules. 39 | ``pybind11::embed`` 40 | for embedding the Python interpreter. 41 | 42 | Python headers, libraries (as needed by platform), and the C++ standard 43 | are attached to the target. 44 | 45 | Advanced targets are also supplied - these are primary for users building 46 | complex applications, and they are available in all modes: 47 | 48 | ``pybind11::headers`` 49 | Just the pybind11 headers and minimum compile requirements. 50 | ``pybind11::pybind11`` 51 | Python headers too. 52 | ``pybind11::python_link_helper`` 53 | Just the "linking" part of ``pybind11:module``, for CMake < 3.15. 54 | ``pybind11::thin_lto`` 55 | An alternative to ``INTERPROCEDURAL_OPTIMIZATION``. 56 | ``pybind11::lto`` 57 | An alternative to ``INTERPROCEDURAL_OPTIMIZATION`` (also avoids thin LTO on clang). 58 | ``pybind11::windows_extras`` 59 | Adds bigobj and mp for MSVC. 60 | 61 | Modes 62 | ===== 63 | 64 | There are two modes provided; classic, which is built on the old Python 65 | discovery packages in CMake, or the new FindPython mode, which uses FindPython 66 | from 3.12+ forward (3.15+ _highly_ recommended). If you set the minimum or 67 | maximum version of CMake to 3.27+, then FindPython is the default (since 68 | FindPythonInterp/FindPythonLibs has been removed via policy `CMP0148`). 69 | 70 | New FindPython mode 71 | ^^^^^^^^^^^^^^^^^^^ 72 | 73 | To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)`` 74 | before finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode, 75 | you can either use the basic targets, or use the FindPython tools: 76 | 77 | .. code-block:: cmake 78 | 79 | find_package(Python COMPONENTS Interpreter Development) 80 | find_package(pybind11 CONFIG) 81 | 82 | # pybind11 method: 83 | pybind11_add_module(MyModule1 src1.cpp) 84 | 85 | # Python method: 86 | Python_add_library(MyModule2 src2.cpp) 87 | target_link_libraries(MyModule2 pybind11::headers) 88 | set_target_properties(MyModule2 PROPERTIES 89 | INTERPROCEDURAL_OPTIMIZATION ON 90 | CXX_VISIBILITY_PRESET ON 91 | VISIBILITY_INLINES_HIDDEN ON) 92 | 93 | If you build targets yourself, you may be interested in stripping the output 94 | for reduced size; this is the one other feature that the helper function gives you. 95 | 96 | Classic mode 97 | ^^^^^^^^^^^^ 98 | 99 | Set PythonLibsNew variables to influence python detection and 100 | CMAKE_CXX_STANDARD to influence standard setting. 101 | 102 | .. code-block:: cmake 103 | 104 | find_package(pybind11 CONFIG REQUIRED) 105 | 106 | # Create an extension module 107 | add_library(mylib MODULE main.cpp) 108 | target_link_libraries(mylib PUBLIC pybind11::module) 109 | 110 | # Or embed the Python interpreter into an executable 111 | add_executable(myexe main.cpp) 112 | target_link_libraries(myexe PUBLIC pybind11::embed) 113 | 114 | 115 | Hints 116 | ===== 117 | 118 | The following variables can be set to guide the search for this package: 119 | 120 | ``pybind11_DIR`` 121 | CMake variable, set to directory containing this Config file. 122 | ``CMAKE_PREFIX_PATH`` 123 | CMake variable, set to root directory of this package. 124 | ``PATH`` 125 | Environment variable, set to bin directory of this package. 126 | ``CMAKE_DISABLE_FIND_PACKAGE_pybind11`` 127 | CMake variable, disables ``find_package(pybind11)`` when not ``REQUIRED``, 128 | perhaps to force internal build. 129 | 130 | Commands 131 | ======== 132 | 133 | pybind11_add_module 134 | ^^^^^^^^^^^^^^^^^^^ 135 | 136 | This module defines the following commands to assist with creating Python modules: 137 | 138 | .. code-block:: cmake 139 | 140 | pybind11_add_module( 141 | [STATIC|SHARED|MODULE] 142 | [THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI] 143 | ... 144 | ) 145 | 146 | Add a module and setup all helpers. You can select the type of the library; the 147 | default is ``MODULE``. There are several options: 148 | 149 | ``OPT_SIZE`` 150 | Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``MinSizeRel``. 151 | ``THIN_LTO`` 152 | Use thin LTO instead of regular if there's a choice (pybind11's selection 153 | is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set). 154 | ``WITHOUT_SOABI`` 155 | Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only). 156 | ``NO_EXTRAS`` 157 | Disable all extras, exit immediately after making the module. 158 | 159 | pybind11_strip 160 | ^^^^^^^^^^^^^^ 161 | 162 | .. code-block:: cmake 163 | 164 | pybind11_strip() 165 | 166 | Strip a target after building it (linux/macOS), called by ``pybind11_add_module``. 167 | 168 | pybind11_extension 169 | ^^^^^^^^^^^^^^^^^^ 170 | 171 | .. code-block:: cmake 172 | 173 | pybind11_extension() 174 | 175 | Sets the Python extension name correctly for Python on your platform, called by 176 | ``pybind11_add_module``. 177 | 178 | pybind11_find_import(module) 179 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 180 | 181 | .. code-block:: cmake 182 | 183 | pybind11_find_import( [VERSION ] [REQUIRED] [QUIET]) 184 | 185 | See if a module is installed. Use the registered name (the one on PyPI). You 186 | can specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if 187 | ``NOPYTHON`` mode is not active. Sets ``module_VERSION`` and ``module_FOUND``. Caches the 188 | result once a valid install is found. 189 | 190 | Suggested usage 191 | =============== 192 | 193 | Using ``find_package`` with version info is not recommended except for release versions. 194 | 195 | .. code-block:: cmake 196 | 197 | find_package(pybind11 CONFIG) 198 | find_package(pybind11 2.9 EXACT CONFIG REQUIRED) 199 | 200 | #]=============================================================================] 201 | @PACKAGE_INIT@ 202 | 203 | # Location of pybind11/pybind11.h 204 | # This will be relative unless explicitly set as absolute 205 | set(pybind11_INCLUDE_DIR "@pybind11_INCLUDEDIR@") 206 | 207 | set(pybind11_LIBRARY "") 208 | set(pybind11_DEFINITIONS USING_pybind11) 209 | set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@") 210 | 211 | check_required_components(pybind11) 212 | 213 | if(TARGET pybind11::python_link_helper) 214 | # This has already been setup elsewhere, such as with a previous call or 215 | # add_subdirectory 216 | return() 217 | endif() 218 | 219 | include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake") 220 | 221 | # Easier to use / remember 222 | add_library(pybind11::headers IMPORTED INTERFACE) 223 | set_target_properties(pybind11::headers PROPERTIES INTERFACE_LINK_LIBRARIES 224 | pybind11::pybind11_headers) 225 | 226 | include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake") 227 | 228 | if(NOT pybind11_FIND_QUIETLY) 229 | message( 230 | STATUS 231 | "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}${pybind11_VERSION_TYPE}\")" 232 | ) 233 | endif() 234 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/pybind11Tools.cmake: -------------------------------------------------------------------------------- 1 | # tools/pybind11Tools.cmake -- Build system for the pybind11 modules 2 | # 3 | # Copyright (c) 2020 Wenzel Jakob 4 | # 5 | # All rights reserved. Use of this source code is governed by a 6 | # BSD-style license that can be found in the LICENSE file. 7 | 8 | # include_guard(global) (pre-CMake 3.10) 9 | if(TARGET pybind11::python_headers) 10 | return() 11 | endif() 12 | 13 | # Built-in in CMake 3.5+ 14 | include(CMakeParseArguments) 15 | 16 | if(pybind11_FIND_QUIETLY) 17 | set(_pybind11_quiet QUIET) 18 | else() 19 | set(_pybind11_quiet "") 20 | endif() 21 | 22 | # If this is the first run, PYTHON_VERSION can stand in for PYBIND11_PYTHON_VERSION 23 | if(NOT DEFINED PYBIND11_PYTHON_VERSION AND DEFINED PYTHON_VERSION) 24 | message(WARNING "Set PYBIND11_PYTHON_VERSION to search for a specific version, not " 25 | "PYTHON_VERSION (which is an output). Assuming that is what you " 26 | "meant to do and continuing anyway.") 27 | set(PYBIND11_PYTHON_VERSION 28 | "${PYTHON_VERSION}" 29 | CACHE STRING "Python version to use for compiling modules") 30 | unset(PYTHON_VERSION) 31 | unset(PYTHON_VERSION CACHE) 32 | elseif(DEFINED PYBIND11_PYTHON_VERSION) 33 | # If this is set as a normal variable, promote it 34 | set(PYBIND11_PYTHON_VERSION 35 | "${PYBIND11_PYTHON_VERSION}" 36 | CACHE STRING "Python version to use for compiling modules") 37 | else() 38 | # Make an empty cache variable. 39 | set(PYBIND11_PYTHON_VERSION 40 | "" 41 | CACHE STRING "Python version to use for compiling modules") 42 | endif() 43 | 44 | # A user can set versions manually too 45 | set(Python_ADDITIONAL_VERSIONS 46 | "3.12;3.11;3.10;3.9;3.8;3.7;3.6" 47 | CACHE INTERNAL "") 48 | 49 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") 50 | find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED ${_pybind11_quiet}) 51 | list(REMOVE_AT CMAKE_MODULE_PATH -1) 52 | 53 | # Makes a normal variable a cached variable 54 | macro(_PYBIND11_PROMOTE_TO_CACHE NAME) 55 | set(_tmp_ptc "${${NAME}}") 56 | # CMake 3.21 complains if a cached variable is shadowed by a normal one 57 | unset(${NAME}) 58 | set(${NAME} 59 | "${_tmp_ptc}" 60 | CACHE INTERNAL "") 61 | endmacro() 62 | 63 | # Cache variables so pybind11_add_module can be used in parent projects 64 | _pybind11_promote_to_cache(PYTHON_INCLUDE_DIRS) 65 | _pybind11_promote_to_cache(PYTHON_LIBRARIES) 66 | _pybind11_promote_to_cache(PYTHON_MODULE_PREFIX) 67 | _pybind11_promote_to_cache(PYTHON_MODULE_EXTENSION) 68 | _pybind11_promote_to_cache(PYTHON_MODULE_DEBUG_POSTFIX) 69 | _pybind11_promote_to_cache(PYTHON_VERSION_MAJOR) 70 | _pybind11_promote_to_cache(PYTHON_VERSION_MINOR) 71 | _pybind11_promote_to_cache(PYTHON_VERSION) 72 | _pybind11_promote_to_cache(PYTHON_IS_DEBUG) 73 | 74 | if(PYBIND11_MASTER_PROJECT) 75 | if(PYTHON_MODULE_EXTENSION MATCHES "pypy") 76 | if(NOT DEFINED PYPY_VERSION) 77 | execute_process( 78 | COMMAND ${PYTHON_EXECUTABLE} -c 79 | [=[import sys; sys.stdout.write(".".join(map(str, sys.pypy_version_info[:3])))]=] 80 | OUTPUT_VARIABLE pypy_version) 81 | set(PYPY_VERSION 82 | ${pypy_version} 83 | CACHE INTERNAL "") 84 | endif() 85 | message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})") 86 | else() 87 | message(STATUS "PYTHON ${PYTHON_VERSION}") 88 | endif() 89 | endif() 90 | 91 | # Only add Python for build - must be added during the import for config since 92 | # it has to be re-discovered. 93 | # 94 | # This needs to be an target to it is included after the local pybind11 95 | # directory, just in case there are multiple versions of pybind11, we want the 96 | # one we expect. 97 | add_library(pybind11::python_headers INTERFACE IMPORTED) 98 | set_property(TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES 99 | "$") 100 | set_property( 101 | TARGET pybind11::pybind11 102 | APPEND 103 | PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers) 104 | 105 | set(pybind11_INCLUDE_DIRS 106 | "${pybind11_INCLUDE_DIR}" "${PYTHON_INCLUDE_DIRS}" 107 | CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located") 108 | 109 | # Python debug libraries expose slightly different objects before 3.8 110 | # https://docs.python.org/3.6/c-api/intro.html#debugging-builds 111 | # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib 112 | if(PYTHON_IS_DEBUG) 113 | set_property( 114 | TARGET pybind11::pybind11 115 | APPEND 116 | PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG) 117 | endif() 118 | 119 | # The <3.11 code here does not support release/debug builds at the same time, like on vcpkg 120 | if(CMAKE_VERSION VERSION_LESS 3.11) 121 | set_property( 122 | TARGET pybind11::module 123 | APPEND 124 | PROPERTY 125 | INTERFACE_LINK_LIBRARIES 126 | pybind11::python_link_helper 127 | "$<$,$>:$>" 128 | ) 129 | 130 | set_property( 131 | TARGET pybind11::embed 132 | APPEND 133 | PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $) 134 | else() 135 | # The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside 136 | # of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are 137 | # target_link_library keywords rather than real libraries. 138 | add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE) 139 | target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES}) 140 | target_link_libraries( 141 | pybind11::module 142 | INTERFACE 143 | pybind11::python_link_helper 144 | "$<$,$>:pybind11::_ClassicPythonLibraries>") 145 | 146 | target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11 147 | pybind11::_ClassicPythonLibraries) 148 | endif() 149 | 150 | function(pybind11_extension name) 151 | # The prefix and extension are provided by FindPythonLibsNew.cmake 152 | set_target_properties( 153 | ${name} 154 | PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" 155 | DEBUG_POSTFIX "${PYTHON_MODULE_DEBUG_POSTFIX}" 156 | SUFFIX "${PYTHON_MODULE_EXTENSION}") 157 | endfunction() 158 | 159 | # Build a Python extension module: 160 | # pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] 161 | # [NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...]) 162 | # 163 | function(pybind11_add_module target_name) 164 | set(options "MODULE;SHARED;EXCLUDE_FROM_ALL;NO_EXTRAS;SYSTEM;THIN_LTO;OPT_SIZE") 165 | cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) 166 | 167 | if(ARG_MODULE AND ARG_SHARED) 168 | message(FATAL_ERROR "Can't be both MODULE and SHARED") 169 | elseif(ARG_SHARED) 170 | set(lib_type SHARED) 171 | else() 172 | set(lib_type MODULE) 173 | endif() 174 | 175 | if(ARG_EXCLUDE_FROM_ALL) 176 | set(exclude_from_all EXCLUDE_FROM_ALL) 177 | else() 178 | set(exclude_from_all "") 179 | endif() 180 | 181 | add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) 182 | 183 | target_link_libraries(${target_name} PRIVATE pybind11::module) 184 | 185 | if(ARG_SYSTEM) 186 | message( 187 | STATUS 188 | "Warning: this does not have an effect - use NO_SYSTEM_FROM_IMPORTED if using imported targets" 189 | ) 190 | endif() 191 | 192 | pybind11_extension(${target_name}) 193 | 194 | # -fvisibility=hidden is required to allow multiple modules compiled against 195 | # different pybind versions to work properly, and for some features (e.g. 196 | # py::module_local). We force it on everything inside the `pybind11` 197 | # namespace; also turning it on for a pybind module compilation here avoids 198 | # potential warnings or issues from having mixed hidden/non-hidden types. 199 | if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET) 200 | set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") 201 | endif() 202 | 203 | if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET) 204 | set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") 205 | endif() 206 | 207 | if(ARG_NO_EXTRAS) 208 | return() 209 | endif() 210 | 211 | if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION) 212 | if(ARG_THIN_LTO) 213 | target_link_libraries(${target_name} PRIVATE pybind11::thin_lto) 214 | else() 215 | target_link_libraries(${target_name} PRIVATE pybind11::lto) 216 | endif() 217 | endif() 218 | 219 | if(DEFINED CMAKE_BUILD_TYPE) # see https://github.com/pybind/pybind11/issues/4454 220 | # Use case-insensitive comparison to match the result of $ 221 | string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) 222 | if(NOT MSVC AND NOT "${uppercase_CMAKE_BUILD_TYPE}" MATCHES DEBUG|RELWITHDEBINFO) 223 | pybind11_strip(${target_name}) 224 | endif() 225 | endif() 226 | 227 | if(MSVC) 228 | target_link_libraries(${target_name} PRIVATE pybind11::windows_extras) 229 | endif() 230 | 231 | if(ARG_OPT_SIZE) 232 | target_link_libraries(${target_name} PRIVATE pybind11::opt_size) 233 | endif() 234 | endfunction() 235 | 236 | # Provide general way to call common Python commands in "common" file. 237 | set(_Python 238 | PYTHON 239 | CACHE INTERNAL "" FORCE) 240 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/setup_global.py.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository) 4 | # This package is targeted for easy use from CMake. 5 | 6 | import glob 7 | import os 8 | import re 9 | 10 | # Setuptools has to be before distutils 11 | from setuptools import setup 12 | 13 | from distutils.command.install_headers import install_headers 14 | 15 | class InstallHeadersNested(install_headers): 16 | def run(self): 17 | headers = self.distribution.headers or [] 18 | for header in headers: 19 | # Remove pybind11/include/ 20 | short_header = header.split("/", 2)[-1] 21 | 22 | dst = os.path.join(self.install_dir, os.path.dirname(short_header)) 23 | self.mkpath(dst) 24 | (out, _) = self.copy_file(header, dst) 25 | self.outfiles.append(out) 26 | 27 | 28 | main_headers = glob.glob("pybind11/include/pybind11/*.h") 29 | detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h") 30 | eigen_headers = glob.glob("pybind11/include/pybind11/eigen/*.h") 31 | stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h") 32 | cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake") 33 | pkgconfig_files = glob.glob("pybind11/share/pkgconfig/*.pc") 34 | headers = main_headers + detail_headers + stl_headers + eigen_headers 35 | 36 | cmdclass = {"install_headers": InstallHeadersNested} 37 | $extra_cmd 38 | 39 | # This will _not_ affect installing from wheels, 40 | # only building wheels or installing from SDist. 41 | # Primarily intended on Windows, where this is sometimes 42 | # customized (for example, conda-forge uses Library/) 43 | base = os.environ.get("PYBIND11_GLOBAL_PREFIX", "") 44 | 45 | # Must have a separator 46 | if base and not base.endswith("/"): 47 | base += "/" 48 | 49 | setup( 50 | name="pybind11_global", 51 | version="$version", 52 | packages=[], 53 | headers=headers, 54 | data_files=[ 55 | (base + "share/cmake/pybind11", cmake_files), 56 | (base + "share/pkgconfig", pkgconfig_files), 57 | (base + "include/pybind11", main_headers), 58 | (base + "include/pybind11/detail", detail_headers), 59 | (base + "include/pybind11/eigen", eigen_headers), 60 | (base + "include/pybind11/stl", stl_headers), 61 | ], 62 | cmdclass=cmdclass, 63 | ) 64 | -------------------------------------------------------------------------------- /source/third_party/pybind11/tools/setup_main.py.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Setup script (in the sdist or in tools/setup_main.py in the repository) 4 | 5 | from setuptools import setup 6 | 7 | cmdclass = {} 8 | $extra_cmd 9 | 10 | setup( 11 | name="pybind11", 12 | version="$version", 13 | download_url='https://github.com/pybind/pybind11/tarball/v$version', 14 | packages=[ 15 | "pybind11", 16 | "pybind11.include.pybind11", 17 | "pybind11.include.pybind11.detail", 18 | "pybind11.include.pybind11.eigen", 19 | "pybind11.include.pybind11.stl", 20 | "pybind11.share.cmake.pybind11", 21 | "pybind11.share.pkgconfig", 22 | ], 23 | package_data={ 24 | "pybind11": ["py.typed"], 25 | "pybind11.include.pybind11": ["*.h"], 26 | "pybind11.include.pybind11.detail": ["*.h"], 27 | "pybind11.include.pybind11.eigen": ["*.h"], 28 | "pybind11.include.pybind11.stl": ["*.h"], 29 | "pybind11.share.cmake.pybind11": ["*.cmake"], 30 | "pybind11.share.pkgconfig": ["*.pc"], 31 | }, 32 | extras_require={ 33 | "global": ["pybind11_global==$version"] 34 | }, 35 | entry_points={ 36 | "console_scripts": [ 37 | "pybind11-config = pybind11.__main__:main", 38 | ], 39 | "pipx.run": [ 40 | "pybind11 = pybind11.__main__:main", 41 | ] 42 | }, 43 | cmdclass=cmdclass 44 | ) 45 | --------------------------------------------------------------------------------