diff --git a/Jenkinsfile b/Jenkinsfile index 02b0adb1..b764229b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,66 +1,144 @@ pipeline { - agent { - dockerfile { - label 'isaac-gpu' - reuseNode true - filename 'Dockerfile.deps' - args '-u root --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' - } - } + agent none triggers { gitlab(triggerOnMergeRequest: true, branchFilterType: 'All') } stages { - stage('Compile') { - steps { - sh '''mkdir -p nvblox/build''' - sh '''mkdir -p nvblox/install''' - sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make -j8 && make install''' - } - } - stage('Test') { - steps { - sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' - } - } - stage('Link Into External Project') { - steps { - dir("nvblox_lib_test") { - git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + stage("Compile & Test Multiplatform") { + parallel { + stage("x86") { + agent { + dockerfile { + label 'isaac-gpu' + reuseNode true + filename 'docker/Dockerfile.deps' + args '-u root --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' + } + } + stages { + stage('Compile x86') { + steps { + sh '''mkdir -p nvblox/build''' + sh '''mkdir -p nvblox/install''' + sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make clean && make -j8 && make install''' + } + } + stage('Test x86') { + steps { + sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' + } + } + stage('Link Into External Project x86') { + steps { + dir("nvblox_lib_test") { + git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + } + sh '''mkdir -p nvblox_lib_test/build''' + sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' + sh '''cd nvblox_lib_test/build && ./min_example''' + } + } + stage("Cleanup x86") { + steps { + // Archive the CTest xml output + archiveArtifacts ( + artifacts: 'nvblox/build/tests/Testing/**/*.xml', + fingerprint: true + ) + + // Process the CTest xml output with the xUnit plugin + xunit ( + testTimeMargin: '3000', + thresholdMode: 1, + thresholds: [ + skipped(failureThreshold: '0'), + failed(failureThreshold: '0') + ], + tools: [CTest( + pattern: 'nvblox/build/tests/Testing/**/*.xml', + deleteOutputFiles: true, + failIfNotNew: false, + skipNoTestFiles: true, + stopProcessingIfError: true + )] + ) + + // Clear the source and build dirs before next run + cleanWs() + } + } + } + } + stage("Jetson 5.0.2") { + agent { + dockerfile { + label 'jetson-5.0.2' + reuseNode true + filename 'docker/Dockerfile.jetson_deps' + args '-u root --runtime nvidia --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' + } + } + stages { + stage('Compile Jetson') { + steps { + sh '''mkdir -p nvblox/build''' + sh '''mkdir -p nvblox/install''' + sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make clean && make -j8 && make install''' + } + } + stage('Test Jetson') { + steps { + sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' + } + } + stage('Link Into External Project Jetson') { + steps { + dir("nvblox_lib_test") { + git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + } + sh '''mkdir -p nvblox_lib_test/build''' + sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' + sh '''cd nvblox_lib_test/build && ./min_example''' + } + } + stage("Cleanup Jetson") { + steps { + archiveArtifacts ( + artifacts: 'nvblox/build/tests/Testing/**/*.xml', + fingerprint: true + ) + + // Process the CTest xml output with the xUnit plugin + xunit ( + testTimeMargin: '3000', + thresholdMode: 1, + thresholds: [ + skipped(failureThreshold: '0'), + failed(failureThreshold: '0') + ], + tools: [CTest( + pattern: 'nvblox/build/tests/Testing/**/*.xml', + deleteOutputFiles: true, + failIfNotNew: false, + skipNoTestFiles: true, + stopProcessingIfError: true + )] + ) + + // Clear the source and build dirs before next run + cleanWs() + } + } + } } - sh '''mkdir -p nvblox_lib_test/build''' - sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' - sh '''cd nvblox_lib_test/build && ./min_example''' } } } post { always { - // Archive the CTest xml output - archiveArtifacts ( - artifacts: 'nvblox/build/tests/Testing/**/*.xml', - fingerprint: true - ) - - // Process the CTest xml output with the xUnit plugin - xunit ( - testTimeMargin: '3000', - thresholdMode: 1, - thresholds: [ - skipped(failureThreshold: '0'), - failed(failureThreshold: '0') - ], - tools: [CTest( - pattern: 'nvblox/build/Testing/**/*.xml', - deleteOutputFiles: true, - failIfNotNew: false, - skipNoTestFiles: true, - stopProcessingIfError: true - )] - ) - - // Clear the source and build dirs before next run - cleanWs() + agent { + label 'isaac-gpu' + } } failure { updateGitlabCommitStatus name: 'build', state: 'failed' diff --git a/README.md b/README.md index b2b84c11..49130b3b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ # nvblox Signed Distance Functions (SDFs) on NVIDIA GPUs. +
+ An SDF library which offers * Support for storage of various voxel types * GPU accelerated agorithms such as: * TSDF construction * ESDF construction + * Meshing * ROS2 interface (see [isaac_ros_nvblox](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_nvblox)) * ~~Python bindings~~ (coming soon) @@ -31,7 +34,7 @@ We depend on: - gtest - glog - gflags (to run experiments) -- CUDA 10.2 - 11.5 (others might work but are untested) +- CUDA 11.0 - 11.6 (others might work but are untested) - Eigen (no need to explicitly install, a recent version is built into the library) - SQLite 3 (for serialization) Please run @@ -69,11 +72,13 @@ you should see a mesh of a room: # Docker -We have several dockerfiles which layer on top of one another for the following purposes: +We have several dockerfiles (in the `docker` subfolder) which layer on top of one another for the following purposes: * **Docker.deps** * * This installs our dependencies. * * This is used in our CI, where the later steps (building and testing) are taken care of by Jenkins (and not docker). +* **Docker.jetson_deps** +* * Same as above, just on the Jetson (Jetpack 5 and above). * **Docker.build** * * Layers on top of Docker.deps. * * This builds our package. @@ -101,13 +106,13 @@ Restart docker ``` sudo systemctl restart docker ``` -Now Let's build Dockerfile.deps docker image. This image install contains our dependacies. +Now Let's build Dockerfile.deps docker image. This image install contains our dependencies. (In case you are running this on the Jetson, simply substitute docker/`Dockerfile.jetson_deps` below and the rest of the instructions remain the same. ``` -docker build -t nvblox_deps -f Dockerfile.deps . +docker build -t nvblox_deps -f docker/Dockerfile.deps . ``` Now let's build the Dockerfile.build. This image layers on the last, and actually builds the nvblox library. ``` -docker build -t nvblox -f Dockerfile.build . +docker build -t nvblox -f docker/Dockerfile.build . ``` Now let's run the 3DMatch example inside the docker. Note there's some additional complexity in the `docker run` command such that we can forward X11 to the host (we're going to be view a reconstruction in a GUI). Run the container using: ``` @@ -120,7 +125,7 @@ apt-get update apt-get install unzip wget http://vision.princeton.edu/projects/2016/3DMatch/downloads/rgbd-datasets/sun3d-mit_76_studyroom-76-1studyroom2.zip -P ~/datasets/3dmatch unzip ~/datasets/3dmatch/sun3d-mit_76_studyroom-76-1studyroom2.zip -d ~/datasets/3dmatch -cd nvblox/nvblox/build/experiments/ +cd nvblox/nvblox/build/executables/ ./fuse_3dmatch ~/datasets/3dmatch/sun3d-mit_76_studyroom-76-1studyroom2/ --esdf_frame_subsampling 3000 --mesh_output_path mesh.ply ``` Now let's visualize. From the same experiments folder run: @@ -131,7 +136,7 @@ python3 ../../visualization/visualize_mesh.py mesh.ply ``` # Additional instructions for Jetson Xavier -These instructions are for a native build on the Jetson Xavier. A Docker based build is coming soon. +These instructions are for a native build on the Jetson Xavier. You can see the instructions above for running in docker. The instructions for the native build above work, with one exception: @@ -156,5 +161,14 @@ sudo apt-get install cmake export OPENBLAS_CORETYPE=ARMV8 ``` +# Building for multiple GPU architectures +By default, the library builds ONLY for the compute capability (CC) of the machine it's being built on. To build binaries that can be used across multiple machines (i.e., pre-built binaries for CI, for example), you can use the `BUILD_FOR_ALL_ARCHS` flag and set it to true. Example: +``` +cmake .. -DBUILD_FOR_ALL_ARCHS=True -DCMAKE_INSTALL_PREFIX=../install/ && make -j8 && make install +``` + +# Building redistributable binaries, with static dependencies +If you want to include nvblox in another CMake project, simply `find_package(nvblox)` should bring in the correct libraries and headers. However, if you want to include it in a different build system such as Bazel, you can see the instructions here: [docs/redistibutable.md]. + # License This code is under an [open-source license](LICENSE) (Apache 2.0). :) diff --git a/Dockerfile.build b/docker/Dockerfile.build similarity index 100% rename from Dockerfile.build rename to docker/Dockerfile.build diff --git a/Dockerfile.deps b/docker/Dockerfile.deps similarity index 100% rename from Dockerfile.deps rename to docker/Dockerfile.deps diff --git a/docker/Dockerfile.jetson_deps b/docker/Dockerfile.jetson_deps new file mode 100644 index 00000000..d218b2d4 --- /dev/null +++ b/docker/Dockerfile.jetson_deps @@ -0,0 +1,20 @@ +FROM nvcr.io/nvidia/l4t-jetpack:r35.1.0 + +# TZData goes first. +RUN apt-get update +ENV TZ Europe/Berlin +ENV DEBIAN_FRONTEND noninteractive +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +RUN apt-get install -y tzdata + +# Install basics. +RUN apt-get update +RUN apt-get install -y ssh git jq gnupg apt-utils software-properties-common build-essential cmake + +# Install dependencies. +RUN apt-get install -y libgoogle-glog-dev libgtest-dev curl libsqlite3-dev + +# Build gtest because gtest doesn't do this for you for some reason. +RUN cd /usr/src/googletest && cmake . && cmake --build . --target install + +ENV DEBIAN_FRONTEND teletype diff --git a/Dockerfile.test b/docker/Dockerfile.test similarity index 100% rename from Dockerfile.test rename to docker/Dockerfile.test diff --git a/docs/Doxyfile b/docs/Doxyfile index 5bf8689b..48c71425 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "project" +PROJECT_NAME = "nvblox" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -44,14 +44,14 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = "Building signed distance fields for robots from sensor data on Nvidia GPUs." # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = ./images/nvblox_logo_64.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -150,7 +150,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -461,7 +461,7 @@ EXTRACT_STATIC = YES # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are @@ -680,7 +680,7 @@ SHOW_FILES = YES # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = NO +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -790,7 +790,10 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../nvblox/include +INPUT = ../README.md \ + pages/ \ + images/ \ + ../nvblox/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -819,7 +822,8 @@ FILE_PATTERNS = *.h \ *.hh \ *.hxx \ *.hpp \ - *.h++ + *.h++ \ + *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -834,7 +838,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -850,7 +854,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = *_impl.h +EXCLUDE_PATTERNS = *_impl.h */traits.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -887,7 +891,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = ./images/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -943,7 +947,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1083,7 +1087,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = NO +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1118,7 +1122,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = doxy_header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1153,7 +1157,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = doxygen-awesome.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1163,7 +1167,7 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = images/nvblox_logo_32.png # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -1204,13 +1208,24 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1439,7 +1454,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. diff --git a/docs/conf.py b/docs/conf.py index c893ba47..e8a29822 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,5 @@ import os +import subprocess name = 'nvblox' @@ -9,37 +10,41 @@ html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -# html_logo = "logo.gif" +subprocess.call('doxygen', shell=True) + +html_logo = "images/nvblox_logo_128.png" source_parsers = { '.md': 'recommonmark.parser.CommonMarkParser', } extensions = [ - 'sphinx.ext.autosectionlabel', 'recommonmark' #'breathe' 'exhale' + 'sphinx.ext.autosectionlabel', 'myst_parser', #'breathe', 'exhale', ] project = name -master_doc = 'index' +master_doc = 'root' # html_theme_options = {'logo_only': True} +html_extra_path = ['doxyoutput/html'] + -# Setup the breathe extension +# # Setup the breathe extension # breathe_projects = {"project": "./doxyoutput/xml"} # breathe_default_project = "project" -# Setup the exhale extension -exhale_args = { - "verboseBuild": False, - "containmentFolder": "./api", - "rootFileName": "library_root.rst", - "rootFileTitle": "Library API", - "doxygenStripFromPath": "..", - "createTreeView": True, - # "exhaleExecutesDoxygen": False, # SWITCH TO TRUE - # "exhaleUseDoxyfile": False, # SWITCH TO TRUE - # "pageLevelConfigMeta": ":github_url: https://github.com/ethz-asl/" + name -} +# # Setup the exhale extension +# exhale_args = { +# "verboseBuild": False, +# "containmentFolder": "./api", +# "rootFileName": "library_root.rst", +# "rootFileTitle": "Library API", +# "doxygenStripFromPath": "..", +# "createTreeView": True, +# "exhaleExecutesDoxygen": True, # SWITCH TO TRUE +# "exhaleUseDoxyfile": True, # SWITCH TO TRUE +# "pageLevelConfigMeta": ":github_url: https://github.com/nvidia-isaac/" + name +# } source_suffix = ['.rst', '.md'] diff --git a/docs/doxy_header.html b/docs/doxy_header.html new file mode 100644 index 00000000..37e6d3a2 --- /dev/null +++ b/docs/doxy_header.html @@ -0,0 +1,57 @@ + + + + + + + + +$projectname: $title +$title + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/docs/doxygen-awesome.css b/docs/doxygen-awesome.css new file mode 100644 index 00000000..121eb0fd --- /dev/null +++ b/docs/doxygen-awesome.css @@ -0,0 +1,2405 @@ +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + + /* page base colors */ + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 8px; + --border-radius-small: 4px; + --border-radius-medium: 6px; + + /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ + --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + + /* font sizes */ + --page-font-size: 15.6px; + --navigation-font-size: 14.4px; + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ + --title-font-size: 22px; + + /* content text properties. These only affect the page content, not the navigation or any other ui elements */ + --content-line-height: 27px; + /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); + + /* colors for various content boxes: @warning, @note, @deprecated @bug */ + --warning-color: #f8d1cc; + --warning-color-dark: #b61825; + --warning-color-darker: #75070f; + --note-color: #faf3d8; + --note-color-dark: #f3a600; + --note-color-darker: #5f4204; + --todo-color: #e4f3ff; + --todo-color-dark: #1879C4; + --todo-color-darker: #274a5c; + --deprecated-color: #ecf0f3; + --deprecated-color-dark: #5b6269; + --deprecated-color-darker: #43454a; + --bug-color: #e4dafd; + --bug-color-dark: #5b2bdd; + --bug-color-darker: #2a0d72; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; + + /* blockquote colors */ + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; + + /* table colors */ + --tablehead-background: #f1f1f1; + --tablehead-foreground: var(--page-foreground-color); + + /* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ + --menu-display: block; + + --menu-focus-foreground: var(--page-background-color); + --menu-focus-background: var(--primary-color); + --menu-selected-background: rgba(0,0,0,.05); + + + --header-background: var(--page-background-color); + --header-foreground: var(--page-foreground-color); + + /* searchbar colors */ + --searchbar-background: var(--side-nav-background); + --searchbar-foreground: var(--page-foreground-color); + + /* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ + --searchbar-height: 33px; + --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); + + /* code block colors */ + --code-background: #f5f5f5; + --code-foreground: var(--page-foreground-color); + + /* fragment colors */ + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; + --fragment-lineheight: 20px; + + /* sidebar navigation (treeview) colors */ + --side-nav-background: #fbfbfb; + --side-nav-foreground: var(--page-foreground-color); + --side-nav-arrow-opacity: 0; + --side-nav-arrow-hover-opacity: 0.9; + + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsable table */ + --tree-item-height: 30px; + + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --toc-font-size: 15px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: .9em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl, p.reference, p.definition { + font-size: var(--page-font-size); +} + +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--primary-color) !important; + font-weight: 500; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + +/* +Title and top navigation +*/ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: 64px; + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + border-color: var(--header-foreground) transparent transparent transparent; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground) transparent transparent transparent; + } + + .sm-dox ul a span.sub-arrow { + border-color: transparent transparent transparent var(--page-foreground-color); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: transparent transparent transparent var(--menu-focus-foreground); + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: var(--page-background-color); + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* +Search box +*/ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; +} + +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { + left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ + label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; + } + + label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; + } +} + +/* +Tree view +*/ + +#side-nav { + padding: 0 !important; + background: var(--side-nav-background); +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } +} + +#nav-tree { + background: transparent; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); +} + +#nav-sync { + bottom: 12px; + right: 12px; + top: auto !important; + user-select: none; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); +} + +.arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + text-align: right; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + background: var(--separator-color); + width: 1px; +} + +/* +Contents +*/ + +div.header { + border-bottom: 1px solid var(--separator-color); + background-color: var(--page-background-color); + background-image: none; +} + +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 225%; + padding: var(--spacing-medium) var(--spacing-large); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + border: none; + padding: 4px 9px; + border-radius: 12px; + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-large); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents > table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents > table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe { + filter: hue-rotate(180deg) invert(); +} + +h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); +} + +.alphachar a { + color: var(--page-foreground-color); +} + +/* +Table of Contents +*/ + +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); + padding: 0 var(--spacing-large); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0 var(--spacing-medium) 0; +} + +div.toc li { + padding: 0; + background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; +} + +div.toc li::before { + display: none; +} + +div.toc ul { + margin-top: 0 +} + +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; +} + + +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform 0.25s ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; + } +} + +/* +Code & Fragments +*/ + +code, div.fragment, pre.fragment { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; +} + +div.fragment, pre.fragment { + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +/* +dl warning, attention, note, deprecated, bug, ... +*/ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt { + color: var(--todo-color-dark); +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + +/* +memitem +*/ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* +reflist +*/ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* +Table +*/ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.doxtable caption { + display: block; +} + +table.fieldtable { + border-collapse: collapse; + width: 100%; +} + +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { + border: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); +} + +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); +} + +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +table.memberdecls { + display: block; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform 0.25s ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } +} + + +/* +Horizontal Rule +*/ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* +Directories +*/ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +table.directory tr.odd { + background-color: transparent; +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; + height: var(--table-line-height); +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* +Class list +*/ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +.classindex dl.even { + background-color: transparent; +} + +/* +Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* +Footer and nav-path +*/ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path li.navelem:after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* +Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* +Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + scrollbar-width: thin; +} + +/* +Optional Dark mode toggle button +*/ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-height); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform .1s ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* +Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* +Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity .1s ease-in-out, color .1s ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} \ No newline at end of file diff --git a/docs/images/nvblox_logo.png b/docs/images/nvblox_logo.png new file mode 100644 index 00000000..9cf09f40 Binary files /dev/null and b/docs/images/nvblox_logo.png differ diff --git a/docs/images/nvblox_logo_128.png b/docs/images/nvblox_logo_128.png new file mode 100644 index 00000000..c2961b13 Binary files /dev/null and b/docs/images/nvblox_logo_128.png differ diff --git a/docs/images/nvblox_logo_32.png b/docs/images/nvblox_logo_32.png new file mode 100644 index 00000000..738a25af Binary files /dev/null and b/docs/images/nvblox_logo_32.png differ diff --git a/docs/images/nvblox_logo_64.png b/docs/images/nvblox_logo_64.png new file mode 100644 index 00000000..69b0b0e2 Binary files /dev/null and b/docs/images/nvblox_logo_64.png differ diff --git a/docs/images/system_diagram.png b/docs/images/system_diagram.png new file mode 100644 index 00000000..abd39567 Binary files /dev/null and b/docs/images/system_diagram.png differ diff --git a/docs/pages/integrators.md b/docs/pages/integrators.md new file mode 100644 index 00000000..b33d6d94 --- /dev/null +++ b/docs/pages/integrators.md @@ -0,0 +1,18 @@ +# Integrators + +An integrator is, very generally, a class that modifies the content of a layers. + +The integrators currently offered can be split into two types: + +* Those which fuse incoming sensor data into a layer. For example, the [TsdfIntegrator](@ref nvblox::ProjectiveTsdfIntegrator) and [ColorIntegrator](@ref nvblox::ProjectiveColorIntegrator) fused depth images and color images into [TsdfLayer](@ref nvblox::TsdfLayer) and [ColorLayer](@ref nvblox::ColorLayer) respectively. +* Those which transform the contents of one layer to update the data in another layer. For example the [EsdfIntegrator](@ref nvblox::EsdfIntegrator) transforms an TSDF in a [TsdfLayer](@ref nvblox::TsdfLayer) into an ESDF in a [EsdfLayer](@ref nvblox::EsdfLayer). + +## API + +The API for the currently available integrators are here: + +* [TsdfIntegrator](@ref nvblox::ProjectiveTsdfIntegrator) +* [ColorIntegrator](@ref nvblox::ProjectiveColorIntegrator) +* [EsdfIntegrator](@ref nvblox::EsdfIntegrator) +* [MeshIntegrator](@ref nvblox::MeshIntegrator) + diff --git a/docs/pages/map.md b/docs/pages/map.md new file mode 100644 index 00000000..188b3098 --- /dev/null +++ b/docs/pages/map.md @@ -0,0 +1,53 @@ +# Map Overview +We implement a hierarchical sparse voxel grid for storing data. At the top level we have the ``LayerCake``, which contains several layers, each of which contains a different type of mapped quantity (eg TSDF and ESDF). A layer is a collection of sparsely allocated blocks. Each block is in charge of mapping a cubular small region of space. Most blocks are composed of many voxels, each of which captures a single value of the mapped quantity (eg the TSDF). + +![Map Structure](images/map_structure.png) + +The API for the various classes implementing a map nvblox map: + +## Voxels + +* [TsdfVoxel](@ref nvblox::TsdfVoxel) +* [EsdfVoxel](@ref nvblox::EsdfVoxel) +* [ColorVoxel](@ref nvblox::ColorVoxel) + +## Blocks + +A template for a block containing voxels. + +* [VoxelBlock](@ref nvblox::VoxelBlock) + +Blocks containing specific voxel types. These are just typedefs of the above voxel blocks. + +* [TsdfBlock](@ref nvblox::TsdfBlock) +* [Esdflock](@ref nvblox::TsdfBlock) +* [ColorBlock](@ref nvblox::TsdfBlock) + +We store the mesh of the environment as a collection of smaller meshes. In particular, a ``MeshLayer`` contains ``MeshBlocks``, each of which contains a mesh of the surfaces in that region contained within that block. Note that we store a mesh per *block*, there are no mesh *voxels*. +Storage of the mesh in this way allows us to perform incremental updates (we only update the mesh in blocks where the underlying TSDF has changed). + +* [MeshBlock](@ref nvblox::MeshBlock>) + +## Layers + +Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock`` s. + +* [BlockLayer](@ref nvblox::BlockLayer) +* [VoxelBlockLayer](@ref nvblox::VoxelBlockLayer) + +Typedefs for layers containing specific block types and voxel block types. + +* [TsdfLayer](@ref nvblox::TsdfLayer) +* [EsdfLayer](@ref nvblox::EsdfLayer) +* [ColorLayer](@ref nvblox::ColorLayer) +* [MeshLayer](@ref nvblox::MeshLayer) + +## Layer Cake + +The ``LayerCake`` combines several layers into a single object. + +* [LayerCake](@ref nvblox::LayerCake) + + + + diff --git a/docs/pages/nvblox_node.rst b/docs/pages/nvblox_node.rst deleted file mode 100644 index 7bb2e792..00000000 --- a/docs/pages/nvblox_node.rst +++ /dev/null @@ -1,158 +0,0 @@ - -.. # Package Reference -.. In this section we give an overview of parameters, inputs, and outputs within this repository and their purpose and settings. - -.. ## nvblox_ros -.. The package centers around the `nvblox_node`, whose parameters, inputs, and outputs are described in detail here. - - -.. ### Published Topics - -.. **mesh** ``nvblox_msgs::msg::Mesh`` \ -.. A visualization topic showing the mesh produced from the TSDF in a form that can be seen in RViz using `nvblox_rviz_plugin`. Set ``max_mesh_update_hz`` to control its update rate. - -.. **pointcloud** ``sensor_msgs::msg::PointCloud2`` \ -.. A pointcloud of the 2D ESDF (Euclidean Signed Distance Field), with intensity as the metric distance to the nearest obstacle. Set ``max_esdf_update_hz`` to control its update rate. - -.. **map_slice** ``nvblox_msgs::msg::DistanceMapSlice`` \ -.. A 2D slice of the ESDF, to be consumed by `nvblox_nav2` package for interfacing with Nav2. Set ``max_esdf_update_hz`` to control its update rate. - -.. ### Subscribed Topics - -.. **tf** ``tf2_msgs::msg::TFMessage`` \ -.. The pose of the sensor relative to the global frame is resolved through TF2. Please see the [ROS2 documentation](https://docs.ros.org/en/foxy/Tutorials/Tf2/Introduction-To-Tf2.html) for more details. - -.. **depth/image** ``sensor_msgs::msg::Image`` \ -.. The input depth image to be integrated. Must be paired with a `camera_info` message below. Supports both floating-point (depth in meters) and uint16 (depth in millimeters, OpenNI format). - -.. **depth/camera_info** ``sensor_msgs::msg::CameraInfo`` \ -.. Required topic along with the depth image; contains intrinsic calibration parameters of the depth camera. - -.. **color/image** ``sensor_msgs::msg::Image`` \ -.. Optional input color image to be integrated. Must be paired with a `camera_info` message below. Only used to color the mesh. - -.. **color/camera_info** ``sensor_msgs::msg::CameraInfo`` \ -.. Optional topic along with the color image above, contains intrinsics of the color camera. - -.. ### Services - -.. **save_ply** ``std_srvs::srv::Empty`` \ -.. This service has an empty request and response. Calling this service will write a mesh to disk at the path specified by the `output_dir` parameter. - -.. ### Parameters - -.. A summary of the user settable parameters. All parameters are listed as: - -.. **Parameter** `Default` \ -.. Description. - -.. #### General Parameters - -.. **voxel_size** `0.05` \ -.. Voxel size (in meters) to use for the map. - -.. **esdf** `true` \ -.. Whether to compute the ESDF (map of distances to the nearest obstacle). - -.. **esdf_2d** `true` \ -.. Whether to compute the ESDF in 2D (true) or 3D (false). - -.. **distance_slice** `true` \ -.. Whether to output a distance slice of the ESDF to be used for path planning. - -.. **mesh** `true` \ -.. Whether to output a mesh for visualization in rviz, to be used with `nvblox_rviz_plugin`. - -.. **global_frame** `map` \ -.. The name of the TF frame to be used as the global frame. - -.. **slice_height** `1.0` \ -.. The *output* slice height for the distance slice and ESDF pointcloud. Does not need to be within min and max height below. In units of meters. - -.. **min_height** `0.0` \ -.. The minimum height, in meters, to consider obstacles part of the 2D ESDF slice. - -.. **max_height** `1.0` \ -.. The maximum height, in meters, to consider obstacles part of the 2D ESDF slice. - -.. **max_tsdf_update_hz** `10.0` \ -.. The maximum rate (in Hz) at which to integrate depth images into the TSDF. A value of 0.0 means there is no cap. - -.. **max_color_update_hz** `5.0` \ -.. The maximum rate (in Hz) at which to integrate color images into the color layer. A value of 0.0 means there is no cap. - -.. **max_mesh_update_hz** `5.0` \ -.. The maximum rate (in Hz) at which to update and color the mesh. A value of 0.0 means there is no cap. - -.. **max_esdf_update_hz** `2.0` \ -.. The maximum rate (in Hz) at which to update the ESDF and output the distance slice. A value of 0.0 means there is no cap. - - -.. #### Integrator Settings -.. **tsdf_integrator_max_integration_distance_m** `10.0` \ -.. The maximum distance, in meters, to integrate the TSDF up to. - -.. **tsdf_integrator_truncation_distance_vox** `4.0` \ -.. The truncation distance, in units of voxels, for the TSDF. - -.. **tsdf_integrator_max_weight** `100.0` \ -.. Maximum weight for the TSDF. Setting this number higher will lead to higher-quality reconstructions but worse performance in dynamic scenes. - -.. **mesh_integrator_min_weight** `1e-4` \ -.. Minimum weight of the TSDF to consider for inclusion in the mesh. - -.. **mesh_integrator_weld_vertices** `false` \ -.. Whether to weld identical vertices together in the mesh. Currently reduces the number of vertices by a factor of 5x, but is quite slow so we do not recommend you use this setting. - -.. **color_integrator_max_integration_distance_m** `10.0` \ -.. Maximum distance, in meters, to integrate the color up to. - -.. **esdf_integrator_min_weight** `1e-4` \ -.. Minimum weight of the TSDF to consider for inclusion in the ESDF. - -.. **esdf_integrator_min_site_distance_vox** `1.0` \ -.. Minimum distance to consider a voxel within a surface for the ESDF calculation. - -.. **esdf_integrator_max_distance_m** `10.0` \ -.. Maximum distance to compute the ESDF up to, in meters. - - -.. ## nvblox_nav2 -.. `nvblox_nav2` consists of two parts: an `nvblox_costmap_layer`, which is a Nav2 costmap plugin, and launch files for running the set-up with Nav2 in the loop (described above). - -.. ### `nvblox_costmap_layer` Parameters -.. **nvblox_map_slice_topic** `/nvblox_node/map_slice` \ -.. Topic to listen for the slice (set via parameters to allow easy configuration from a parameter file). - -.. **max_obstacle_distance** `1.0` \ -.. Maximum distance from the surface to consider something to have a collision cost, in meters. This is *NOT* in addition to the inflation distance, but the total. - -.. **inflation_distance** `0.5` \ -.. Distance to inflate all obstacles by, in meters. - -.. # Troubleshooting - -.. ## Reconstruction without the planner (troubleshooting) -.. If something isn't working, or as a quick sanity check, you can run reconstruction without the planner. - -.. Use the `carter_sim.launch.py` launch file parameters `run\_rviz` and `run\_nav2` to turn on and off running rviz and nav2. To run the reconstruction without the planner (but with rviz), run the following: -.. ``` -.. ros2 launch nvblox_nav2 carter_sim.launch.py run_rviz:=true run_nav2:=false -.. ``` - -.. Now, command the robot to spin in place. In another terminal, source your ROS2 workspace again and enter: -.. ``` -.. ros2 topic pub /cmd_vel geometry_msgs/Twist '{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.1}}' -.. ``` -.. You should see the robot spin in a circle and reconstruct its environment. - - -.. ## Do you have a connection to Isaac Sim? -.. A quick way to check if ROS2 is communicating correctly with Isaac Sim is to check whether the depth images are being sent. - -.. ``` -.. ros2 topic hz /left/depth -.. ``` - -.. If this does not receive any messages, then something is wrong with ROS2's connection to Isaac Sim. Either the file hasn't been set up correctly (make sure to run `nvblox_isaac_sim/omniverse_scripts/carter_warehouse.py` rather than opening an OV scene manually), or the scene is paused, or there are different ROS2 Domain IDs at play. - diff --git a/docs/pages/technical.md b/docs/pages/technical.md new file mode 100644 index 00000000..c918f260 --- /dev/null +++ b/docs/pages/technical.md @@ -0,0 +1,26 @@ +# Technical Details + +## Input/Outputs + +Here we discuss the inputs you have to provide to nvblox, and the outputs it produces for downstream tasks. This is the default setup within ROS2 for 2D navigation, but note that other outputs are possible (such as the full 3D distance map). + +_Inputs_: +* **Depth Images**: (@ref nvblox::Image) We require input from a sensor supplying depth per pixel. Examples of such sensors are the Intel Realsense series and Kinect cameras. +* **Camera Intrinsics**: (@ref nvblox::Camera) The intrinsics associated with the camera that generated the depth (or color) image. +* **Sensor Pose**: (@ref nvblox::Transform) We require localization of the depth sensor as input to nvblox +* [Optional] **Color Images**: (@ref nvblox::Image) These can be used to color the reconstruction for visualization. +* [Optional] **LIDAR**: (@ref nvblox::Lidar) Optionally or instead of Depth images, we can also consume LIDAR pointclouds which are reprojected to a cylindrical depth image based on the LIDAR intrinsics specified in this datatype. + +_Outputs_: +* **Distance map slice**: (@ref nvblox::EsdfLayer) A 2D map that expresses the distance at each point from objects reconstructed in the environment. This is typically used by a planner to compute a collision cost map. +* **Mesh**: (@ref nvblox::MeshLayer) We output a mesh for visualization in RVIZ. + +The figure below shows a simple system utilizing nvblox for path planning. + +![System Diagram](images/system_diagram.png) + +## (Brief) Technical Details + +Nvblox builds the reconstructed map in the form of a Truncated Signed Distance Function (TSDF) stored in a 3D voxel grid. This approach is similar to 3D occupancy grid mapping approaches in which occupancy probabilities are stored at each voxel. In contrast however, TSDF-based approaches (like nvblox) store the (signed) distance to the closest surface at each voxel. The surface of the environment can then be extracted as the zero-level set of this voxelized function. Typically TSDF-based reconstructions provide higher quality surface reconstructions. + +In addition to their use in reconstruction, distance fields are also useful for path planning because they provide an immediate means of checking whether potential future robot positions are in collision. This fact, the utility of distance functions for both reconstruction and planning, motivates their use in nvblox (a reconstruction library for path planning). diff --git a/docs/pages/technical.rst b/docs/pages/technical.rst deleted file mode 100644 index ab2be9b6..00000000 --- a/docs/pages/technical.rst +++ /dev/null @@ -1,25 +0,0 @@ -# Input/Outputs - -Here we discuss the inputs you have to provide to nvblox, and the outputs it produces for downstream tasks. - -Inputs: -* **Depth Images**: We require input from a sensor supplying depth per pixel. Examples of such sensors are the Intel Realsense series and Kinect cameras. -* **Sensor Pose**: We require localization of the depth sensor as input to nvblox -* [Optional] **Color Images**: These can be used to color the reconstruction for visualization. - -Outputs: -* **Distance map slice**: A 2D map that expresses the distance at each point from objects reconstructed in the environment. This is typically used by a planner to compute a collision cost map. -* **Mesh**: We output a mesh for visualization in RVIZ. - -The figure below shows a simple system utilizing nvblox for path planning. - -
- - - - -# (Brief) Technical Details - -Nvblox builds the reconstructed map in the form of a Truncated Signed Distance Function (TSDF) stored in a 3D voxel grid. This approach is similar to 3D occupancy grid mapping approaches in which occupancy probabilities are stored at each voxel. In contrast however, TSDF-based approaches (like nvblox) store the (signed) distance to the closest surface at each voxel. The surface of the environment can then be extracted as the zero-level set of this voxelized function. Typically TSDF-based reconstructions provide higher quality surface reconstructions. - -In addition to their use in reconstruction, distance fields are also useful for path planning because they provide an immediate means of checking whether potential future robot positions are in collision. This fact, the utility of distance functions for both reconstruction and planning, motivates their use in nvblox (a reconstruction library for path planning). diff --git a/docs/redistributable.md b/docs/redistributable.md new file mode 100644 index 00000000..cb345766 --- /dev/null +++ b/docs/redistributable.md @@ -0,0 +1,51 @@ +# Redistributable Building +This will walk you through how to build a single libnvblox shared library with only static dependencies. The dependencies must be built manually with -fPIC (position independent code) and linked as static libraries. +You generally shouldn't need to do this except for building nvblox to be included in Bazel for example; the exported targets should work fine for inclusion in CMake projects. + +## Step 1: Install dependencies +**Sqlite3**: +Download here: https://www.sqlite.org/2022/sqlite-autoconf-3390400.tar.gz + +Unzip & build using this command: +``` +CFLAGS=-fPIC ./configure --prefix=/home/USERNAME/code/external/sqlite-autoconf-3390400/install/ +``` + +**glog**: +Download here: https://github.com/google/glog/archive/refs/tags/v0.4.0.zip + +Unzip & build using this command: +``` +mkdir build install +cd build +cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ +-DCMAKE_INSTALL_PREFIX=/home/USERNAME/code/external/glog-0.4.0/install/ \ +-DWITH_GFLAGS=OFF -DBUILD_SHARED_LIBS=OFF \ +&& make -j8 && make install +``` + +**gflags**: +Download here: https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip + +Unzip & build using this command: +``` +mkdir build install +cd build +cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ +-DCMAKE_INSTALL_PREFIX=/home/USERNAME/code/external/gflags-2.2.2/install/ \ +-DGFLAGS_BUILD_STATIC_LIBS=ON -DGFLAGS=google \ +&& make -j8 && make install +``` + +## Step 2: Build nvblox +Build nvblox with the paths set to where you've unzipped and built the dependencies: +``` +cd nvblox/ +mkdir build install +cmake .. -DCMAKE_INSTALL_PREFIX=/home/helen/code/nvblox/nvblox/install/ \ +-DBUILD_FOR_ALL_ARCHS=TRUE -DBUILD_REDISTRIBUTABLE=TRUE \ +-DSQLITE3_BASE_PATH="/home/USERNAME/code/external/sqlite-autoconf-3390400/install/" \ +-DGLOG_BASE_PATH="/home/USERNAME/code/external/glog-0.4.0/install/" \ +-DGFLAGS_BASE_PATH="/home/USERNAME/code/external/gflags-2.2.2/install/" \ +&& make -j8 && make install +``` \ No newline at end of file diff --git a/docs/root.rst b/docs/root.rst new file mode 100644 index 00000000..50cba87b --- /dev/null +++ b/docs/root.rst @@ -0,0 +1,8 @@ +======= +Table of Contents +======= + +.. toctree:: + :maxdepth: 1 + :glob: + root diff --git a/docs/pages/examples/core_example.rst b/docs/rst/examples/core_example.rst similarity index 100% rename from docs/pages/examples/core_example.rst rename to docs/rst/examples/core_example.rst diff --git a/docs/pages/examples/index.rst b/docs/rst/examples/index.rst similarity index 100% rename from docs/pages/examples/index.rst rename to docs/rst/examples/index.rst diff --git a/docs/pages/examples/ros_example.rst b/docs/rst/examples/ros_example.rst similarity index 100% rename from docs/pages/examples/ros_example.rst rename to docs/rst/examples/ros_example.rst diff --git a/docs/index.rst b/docs/rst/index.rst similarity index 74% rename from docs/index.rst rename to docs/rst/index.rst index 7e1f72d6..384ed59d 100644 --- a/docs/index.rst +++ b/docs/rst/index.rst @@ -1,5 +1,5 @@ ======= -nvblox +Introduction to nvblox ======= Nvblox is a package for building a 3D reconstruction of the environment around your robot from sensor observations in real-time. The reconstruction is intended to be used by path planners to generate collision-free paths. Under the hood, nvblox uses NVIDIA CUDA to accelerate this task to allow operation at real-time rates. This repository contains ROS2 integration for the nvblox core library. @@ -12,27 +12,14 @@ Nvblox is a package for building a 3D reconstruction of the environment around y .. |pic2| image:: /images/nvblox_navigation_trim.gif :width: 45% -**Left**: nvblox used for reconstruction on a scan from the `Sun3D Dataset `_. **Right**: the nvblox ROS2 wrapper used to construct a costmap for `ROS2 Nav2 `_ for navigating of a robot inside `Isaac Sim `_. +**Left**: nvblox used for reconstruction on a scan from the `Sun3D Dataset `_. +**Right**: the nvblox ROS2 wrapper used to construct a costmap for `ROS2 Nav2 `_ for navigating of a robot inside `Isaac Sim `_. Nvblox is composed of two packages * `nvblox Core Library `_ Contains the core C++/CUDA reconstruction library. * `nvblox ROS2 Interface `_ Contains a ROS2 wrapper and integrations for simulation and path planning. Internally builds the core library. -.. toctree:: - :maxdepth: 1 - :caption: Getting Started - - pages/installation/index - pages/examples/index - - .. :glob: - - .. pages/* - - .. api/library_root - - diff --git a/docs/pages/installation/core.rst b/docs/rst/installation/core.rst similarity index 100% rename from docs/pages/installation/core.rst rename to docs/rst/installation/core.rst diff --git a/docs/pages/installation/index.rst b/docs/rst/installation/index.rst similarity index 100% rename from docs/pages/installation/index.rst rename to docs/rst/installation/index.rst diff --git a/docs/pages/installation/ros.rst b/docs/rst/installation/ros.rst similarity index 100% rename from docs/pages/installation/ros.rst rename to docs/rst/installation/ros.rst diff --git a/docs/pages/integrators.rst b/docs/rst/integrators.rst similarity index 100% rename from docs/pages/integrators.rst rename to docs/rst/integrators.rst diff --git a/docs/pages/map.rst b/docs/rst/map.rst similarity index 98% rename from docs/pages/map.rst rename to docs/rst/map.rst index 5220da2b..bcc12d90 100644 --- a/docs/pages/map.rst +++ b/docs/rst/map.rst @@ -37,7 +37,7 @@ Storage of the mesh in this way allows us to perform incremental updates (we onl Layers ====== -Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock``s. +Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock`` s. * :ref:`BlockLayer