From 37a8c9dabe8cb801654b51980d642a1618705b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20N=C3=BCtzi?= Date: Wed, 23 Sep 2020 22:04:16 +0200 Subject: [PATCH] Build fixes - eigen3 is found by config mode - set compile options on every example as well example: asan needs to load first! - remove warnings --- .vscode/settings.json | 1 - CMakeLists.txt | 10 +- README.md | 310 ++++++++++++--------- cmake/FindEigen3.cmake | 83 ------ example/approxMVBB/CMakeLists.txt | 2 + example/kdTreeFiltering/CMakeLists.txt | 2 + example/kdTreeFiltering/src/main.cpp | 4 +- example/libraryUsage/CMakeLists.txt | 3 +- external/Diameter/src/EstimateDiameter.cpp | 4 - 9 files changed, 186 insertions(+), 233 deletions(-) delete mode 100644 cmake/FindEigen3.cmake diff --git a/.vscode/settings.json b/.vscode/settings.json index 2eb6f4e3..2cfc5d28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,5 +34,4 @@ "unordered_set": "cpp", "typeinfo": "cpp" }, - "cmake.configureArgs": ["-DPugiXML_DIR=/usr/local/opt/pugixml/lib/cmake/pugixml"] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 569763bc..9a52b99b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ set(ApproxMVBB_XML_SUPPORT OFF CACHE BOOL "Build library with XML support.") #======================================================================= # Dependencies ========================================================= -find_package(Eigen3 REQUIRED) +find_package(Eigen3 CONFIG REQUIRED) add_library(eigenLib INTERFACE IMPORTED) set_property(TARGET eigenLib PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${EIGEN3_INCLUDE_DIR}) list(APPEND ApproxMVBB_LIBS_DEP_PUBLIC eigenLib) @@ -158,8 +158,8 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) endif() if(${UNIX}) include(GNUInstallDirs) - set(ApproxMVBB_INC_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") - set(ApproxMVBB_RUNTIME_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") + set(ApproxMVBB_INC_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") + set(ApproxMVBB_RUNTIME_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") set(ApproxMVBB_LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") set(ApproxMVBB_ARCHIVE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") set(ApproxMVBB_FRAMEWORK_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") @@ -168,10 +168,10 @@ if(${UNIX}) set(ApproxMVBB_CMAKE_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/ApproxMVBB/cmake") set(ApproxMVBB_ADDITIONAL_FILES_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/ApproxMVBB") - + elseif(${WIN32}) set(ApproxMVBB_INC_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") - set(ApproxMVBB_RUNTIME_INSTALL_DIR "bin") + set(ApproxMVBB_RUNTIME_INSTALL_DIR "bin") set(ApproxMVBB_LIBRARY_INSTALL_DIR "bin") set(ApproxMVBB_ARCHIVE_INSTALL_DIR "lib") set(ApproxMVBB_FRAMEWORK_INSTALL_DIR "bin") diff --git a/README.md b/README.md index 1032761b..653fccd3 100644 --- a/README.md +++ b/README.md @@ -1,132 +1,153 @@ -ApproxMVBB -========== +# ApproxMVBB -![C++](https://img.shields.io/badge/c%2B%2B-11/14-green.svg) -![Deps](https://img.shields.io/badge/dependencies-eigen3,meta,[pugixml,python3]-blue.svg) +![C++](https://img.shields.io/badge/c%2B%2B-11/14-green.svg) +![Deps](https://img.shields.io/badge/dependencies-eigen3,meta,[pugixml,python3]-blue.svg) ![System](https://img.shields.io/badge/system-linux,osx,{windows}-lightgrey.svg) **Status** -| Build | UnitTests | -| ------| --------- | -|[![Build Status](https://travis-ci.org/gabyx/ApproxMVBB.svg?branch=master)](https://travis-ci.org/gabyx/ApproxMVBB)| [![Build Status](https://travis-ci.org/gabyx/ApproxMVBB.svg?branch=unitTests)](https://travis-ci.org/gabyx/ApproxMVBB) | +| Build | UnitTests | +| ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| [![Build Status](https://travis-ci.org/gabyx/ApproxMVBB.svg?branch=master)](https://travis-ci.org/gabyx/ApproxMVBB) | [![Build Status](https://travis-ci.org/gabyx/ApproxMVBB.svg?branch=unitTests)](https://travis-ci.org/gabyx/ApproxMVBB) | [Homepage](http://gabyx.github.io/ApproxMVBB/) ----------------------------------------- -Fast algorithms to compute an approximation of the minimal volume oriented bounding box of a point cloud in 3D. ----------------------------------------- +--- + +## Fast algorithms to compute an approximation of the minimal volume oriented bounding box of a point cloud in 3D. Computing the minimal volume oriented bounding box for a given point cloud in 3D is a hard problem in computer science. Exact algorithms are known and of cubic order in the number of points in 3D. A faster exact algorithm is currently not know. However, for lots of applications an approximation of the minimum volume oriented bounding box is acceptable and already accurate enough. This project was developed for research in [Granular Rigidbody Dynamics](http://gabyx.github.io/GRSFramework/). -This small standard compliant C++11 library can either be built into a shared object library -or directly be included in an existing C++ project. +This small standard compliant C++11 library can either be built into a shared object library +or directly be included in an existing C++ project. I am not especially proud of the underlying code as it was written years ago, nevertheless consider PR for refactoring and clean ups are very welcome! This library includes code for : - + - computing an approximation of an oriented minimal volume box (multithreading support: OpenMP), - computing the convex hull of a point cloud in 2d, - computing the minimal area rectangle of a 2d point cloud, - 2d projections of point clouds, -- fast building a kD-Tree (n-dimensional, templated) with sophisticated splitting techniques which optimizes a +- fast building a kD-Tree (n-dimensional, templated) with sophisticated splitting techniques which optimizes a quality criteria during the splitting process, - computing the k-nearest neighbors to a given point (kNN search) via kd-Tree. - fast statistical outlier filtering of point clouds via (nearest neighbor search, kD-Tree). -

---------------------------- -Installation & Dependencies ---------------------------- -To build the library, the tests and the example you need the build tool [cmake]( -http://www.cmake.org). +--- + +## Installation & Dependencies + +To build the library, the tests and the example you need the build tool [cmake](http://www.cmake.org). This library has these light-weight required dependencies: - [Eigen](http://eigen.tuxfamily.org) at least version 3. + - With homebrew or linuxbrew: `brew install eigen3` - [meta](https://github.com/ericniebler/meta) + - Install optional: Gets downloaded and used during build. and theses optional dependecies: - [pugixml](https://github.com/zeux/pugixml) - - install with ``#define PUGIXML_HAS_LONG_LONG`` enabled in `pugiconfig.hpp`. - - only needed if cmake variable `ApproxMVBB_XML_SUPPORT=ON` (default=`OFF`). + - With homebrew or linuxbrew: `brew install pugixml` + - install with `#define PUGIXML_HAS_LONG_LONG` enabled in `pugiconfig.hpp`. + - only needed if cmake variable `ApproxMVBB_XML_SUPPORT=ON` (default=`OFF`). - [python3](https://www.python.org/downloads/) only needed for visualization purposes. Download these and install it on your system. Download the latest ApproxMVBB code: + ```bash - git clone https://github.com/gabyx/ApproxMVBB.git ApproxMVBB + git clone https://github.com/gabyx/ApproxMVBB.git ApproxMVBB ``` + Make a build directory and navigate to it: + ```bash mkdir Build cd Build ``` + Invoke cmake in the Build directory: + ```bash cmake ../ApproxMVBB ``` -The cmake script tries to find [Eigen](http://eigen.tuxfamily.org),[meta](https://github.com/ericniebler/meta) and [pugixml](https://github.com/zeux/pugixml) -If you installed these in a system wide folder (e.g ``/usr/local/``) this should succeed without any problems. + +The cmake script tries to find [Eigen](http://eigen.tuxfamily.org),[meta](https://github.com/ericniebler/meta) and [pugixml](https://github.com/zeux/pugixml) +If you installed these in a system wide folder (e.g `/usr/local/`) this should succeed without any problems. In the `CMakeCache.txt` file (or over the console by `-D=ON`) you can specify what you want to build, the following options are availabe: -- ``ApproxMVBB_BUILD_LIBRARY``, -- ``ApproxMVBB_BUILD_TESTS`` -- ``ApproxMVBB_BUILD_EXAMPLE`` -- ``ApproxMVBB_BUILD_BENCHMARKS`` + +- `ApproxMVBB_BUILD_LIBRARY`, +- `ApproxMVBB_BUILD_TESTS` +- `ApproxMVBB_BUILD_EXAMPLE` +- `ApproxMVBB_BUILD_BENCHMARKS` - etc. See the marked red options after configuring in cmake-gui. To install the library and the header files at a specific location `/usr/local/` run cmake with: + ```bash cmake -DCMAKE_INSTALL_PREFIX="/usr/local/" ../ApproxMVBB ``` + Finally, build and install the project: + ```bash make all make install -``` +``` + By default the multithreading support is enabled if OpenMP is found! (see [Multithreading Support](#multithreading-support)) -To build in parallel use the ``-jN`` flag in the `make` command, where ``N``denotes the number of parallel threads to use, or use the Ninja Generator which already uses maximum threads your system offers. +To build in parallel use the `-jN` flag in the `make` command, where `N`denotes the number of parallel threads to use, or use the Ninja Generator which already uses maximum threads your system offers. + +**CMake FindScripts** +The installation installs also scripts `approxmvbb-config.cmake` and `approxmvbb-config-version.cmake` into the `lib/cmake` folder. To include the library in another project the only thing you need to add in your cmake script is -**CMake FindScripts** -The installation installs also scripts ``approxmvbb-config.cmake`` and ``approxmvbb-config-version.cmake`` into the ``lib/cmake`` folder. To include the library in another project the only thing you need to add in your cmake script is ```cmake find_package(ApproxMVBB [version] [COMPONENTS [SUPPORT_KDTREE] [SUPPORT_XML] ] [Required] ) ``` + which defines the following targets if ApproxMVBB has been found successfully: + ```cmake ApproxMVBB::Core # Main target to link with! - ApproxMVBB::KdTreeSupport # Optional target for KdTree support to link with (only available if installed with this supported!) - ApproxMVBB::XMLSupport # Optional target for XML support to link with (only available if installed with this supported!) -``` + ApproxMVBB::KdTreeSupport # Optional target for KdTree support to link with (only available if installed with this supported!) + ApproxMVBB::XMLSupport # Optional target for XML support to link with (only available if installed with this supported!) +``` + The components `SUPPORT_KDTREE` additionally loads the dependency [meta](https://github.com/ericniebler/meta) for the `KdTree.hpp` header and `SUPPORT_XML` loads [pugixml](https://github.com/zeux/pugixml) for the `KdTreeXml.hpp` header. -If you installed the library into non-system generic location you can set the cmake variable ``$ApproxMVBB_DIR`` before invoking the ``find_library`` command: +If you installed the library into non-system generic location you can set the cmake variable `$ApproxMVBB_DIR` before invoking the `find_library` command: + ```cmake set(ApproxMVBB_DIR "path/to/installation/lib/cmake") find_package(ApproxMVBB [version] [Required] ) ``` -See the example `example/libraryUsage` which should be configured as a separate build, and the example `example/kdTreeFiltering` for more information on how to + +See the example `example/libraryUsage` which should be configured as a separate build, and the example `example/kdTreeFiltering` for more information on how to set up the dependencies! --------------------------- -Supported Platforms --------------------------- -The code has been tested on Linux and OS X with compilers ``clang`` and ``gcc``. +--- + +## Supported Platforms + +The code has been tested on Linux and OS X with compilers `clang` and `gcc`. It should work for Windows as well, but has not been tested properly. Under Visual Studio 15 it seems to build. ---------------------------- -Example Usage: Approximation MVBB ---------------------------- -Please see the ``example/approxMVBB/main.cpp`` in the source directory. -Given a point cloud with ``n=10000`` points sampled in the unit cube in 3D +--- + +## Example Usage: Approximation MVBB + +Please see the `example/approxMVBB/main.cpp` in the source directory. +Given a point cloud with `n=10000` points sampled in the unit cube in 3D we compute an approximation of the minimum volume bounding volume by the following calls: + ```C++ #include #include "ApproxMVBB/ComputeApproxMVBB.hpp" @@ -140,16 +161,18 @@ we compute an approximation of the minimum volume bounding volume by the followi return 0; } ``` -The returned object oriented bounding box ``oobb`` contains the lower ``oobb.m_minPoint`` and upper point ``oobb.m_maxPoint`` expressed in the coordinate frame K of the bounding box. The bounding box also stores the rotation matrix from the world frame to the object frame K as a quaternion ``oobb.m_q_KI`` . The rotation matrix ``R_KI`` from frame I to frame K can be obtained by ``oobb.m_q_KI.matrix()`` (see ``Eigen::Quaternion``). This rotation matrix ``R_KI`` corresponds to a coordinate transformation A_IK which transforms coordinates from frame K to coordinates in frame I. Thereforce, to get the lower point expressed in the coordinate frame I this yields: + +The returned object oriented bounding box `oobb` contains the lower `oobb.m_minPoint` and upper point `oobb.m_maxPoint` expressed in the coordinate frame K of the bounding box. The bounding box also stores the rotation matrix from the world frame to the object frame K as a quaternion `oobb.m_q_KI` . The rotation matrix `R_KI` from frame I to frame K can be obtained by `oobb.m_q_KI.matrix()` (see `Eigen::Quaternion`). This rotation matrix `R_KI` corresponds to a coordinate transformation A_IK which transforms coordinates from frame K to coordinates in frame I. Thereforce, to get the lower point expressed in the coordinate frame I this yields: ```C++ - ApproxMVBB::Vector3 p = oobb.m_q_KI * oobb.m_minPoint // A_IK * oobb.m_minPoint + ApproxMVBB::Vector3 p = oobb.m_q_KI * oobb.m_minPoint // A_IK * oobb.m_minPoint ``` -**Degenerate OOBB:** -The returned bounding box might have a degenerated extent in some axis directions depending on the input points (e.g. 3 points defines a plane which is the minimal oriented bounding box with zero volume). The function ``oobb.expandToMinExtentRelative(0.1);`` is a post processing function to enlarge the bounding box by a certain percentage of the largest extent (if existing, otherwise a default value is used). -**Points Outside of the final OOBB:** -Because the algorithm works internally with a sample of the point cloud, the resulting OOBB might not contain all points of the original point cloud! To compensate for this an additional loop is required: +**Degenerate OOBB:** +The returned bounding box might have a degenerated extent in some axis directions depending on the input points (e.g. 3 points defines a plane which is the minimal oriented bounding box with zero volume). The function `oobb.expandToMinExtentRelative(0.1);` is a post processing function to enlarge the bounding box by a certain percentage of the largest extent (if existing, otherwise a default value is used). + +**Points Outside of the final OOBB:** +Because the algorithm works internally with a sample of the point cloud, the resulting OOBB might not contain all points of the original point cloud! To compensate for this an additional loop is required: ```C++ ApproxMVBB::Matrix33 A_KI = oobb.m_q_KI.matrix().transpose(); @@ -159,147 +182,157 @@ Because the algorithm works internally with a sample of the point cloud, the re } ``` -**Function Parameters & How It Works:** +**Function Parameters & How It Works:** The most important function: + ```C++ - ApproxMVBB::approximateMVBB(pts, - epsilon, - pointSamples, + ApproxMVBB::approximateMVBB(pts, + epsilon, + pointSamples, gridSize, - mvbbDiamOptLoops, + mvbbDiamOptLoops, mvbbGridSearchOptLoops) ``` + computes an approximation of the minimal volume bounding box in the following steps: -1. **An approximation of the diameter** (direction which realizes the diameter: ``z`` ) of the points ``pts`` is computed. - The value ``epsilon`` is the absolute tolerance for - the approximation of the diameter and has the same units as the points ``pts`` (in the example 0.001 meter) -2. The points are projected into the plane perpendicular to the direction ``z`` -3. An approximation of the diameter of the projected points in 2D is computed (direction ``x`` ) -4. **The initial approximate bounding box** ``A`` is computed in the orthogonal frame ``[x,y,z]`` -5. **A first optional optimization loop** is performed (parameter ``mvbbDiamOptLoops`` specifies how many loops) - by computing the minimal volume bounding box over a direction ``t`` where the direction ``t`` - is choosen sequentially from the current optimal bounding box solution. The algorithm starts with the directions of the box ``A``. *This optimization works with all points in ``pts`` and might use a lot of time* -5. **The initial bounding box** ``A`` is used as a tight fit around the points ``pts`` - to compute a **representative sample** ``RS`` of the point cloud. The value ``pointSamples`` +1. **An approximation of the diameter** (direction which realizes the diameter: `z` ) of the points `pts` is computed. + The value `epsilon` is the absolute tolerance for + the approximation of the diameter and has the same units as the points `pts` (in the example 0.001 meter) +2. The points are projected into the plane perpendicular to the direction `z` +3. An approximation of the diameter of the projected points in 2D is computed (direction `x` ) +4. **The initial approximate bounding box** `A` is computed in the orthogonal frame `[x,y,z]` +5. **A first optional optimization loop** is performed (parameter `mvbbDiamOptLoops` specifies how many loops) + by computing the minimal volume bounding box over a direction `t` where the direction `t` + is choosen sequentially from the current optimal bounding box solution. The algorithm starts with the directions of the box `A`. _This optimization works with all points in `pts` and might use a lot of time_ +6. **The initial bounding box** `A` is used as a tight fit around the points `pts` + to compute a **representative sample** `RS` of the point cloud. The value `pointSamples` defines how many points are used for the exhaustive grid search procedure in the next step -6. **An exhaustive grid search** (value ``gridSize`` specifies the x,y,z dimension of the grid defined by the bounding box ``A``) is performed. +7. **An exhaustive grid search** (value `gridSize` specifies the x,y,z dimension of the grid defined by the bounding box `A`) is performed. This search is a simple loop over all grid directions (see Gill Barequet, and Sariel Har-Peled [1]) to find a even smaller bounding box. - For each grid direction ``g`` the minimal bounding box of the projected points in direction ``g`` is computed. This consists - of finding the minimal rectangle (axis ``u`` and ``v`` in world frame) of the projected point cloud in the plane perpendicular to direction ``g``. The minimal bounding box ``G`` in direction ``g`` can be computed from the basis ``(u,v,g)`` and is a candidate for the overall minimization problem. - Each found bounding box candidate ``G`` and its directions ``(u,v,g)`` can be used as a starting point for a **second optional optimization loop** (parameter ``mvbbGridSearchOptLoops``, same algorithm as in step 5 but with less points, namely ``RS`` ). -7. The final approximation for the minimal volume bounding box (minimal volume over all computed candidates) is returned. :poop: + For each grid direction `g` the minimal bounding box of the projected points in direction `g` is computed. This consists + of finding the minimal rectangle (axis `u` and `v` in world frame) of the projected point cloud in the plane perpendicular to direction `g`. The minimal bounding box `G` in direction `g` can be computed from the basis `(u,v,g)` and is a candidate for the overall minimization problem. + Each found bounding box candidate `G` and its directions `(u,v,g)` can be used as a starting point for a **second optional optimization loop** (parameter `mvbbGridSearchOptLoops`, same algorithm as in step 5 but with less points, namely `RS` ). +8. The final approximation for the minimal volume bounding box (minimal volume over all computed candidates) is returned. :poop: + +--- ---------------------------- -Example Usage: Generating a KdTree and Outlier Filtering ---------------------------- +## Example Usage: Generating a KdTree and Outlier Filtering -The library includes a fast KdTree implementation (which is not claimed to be ultimativly fast and absolutely memory efficient, -but was written to fulfill this aspects to a certain level, real benchmarks still need to be done, the implementation +The library includes a fast KdTree implementation (which is not claimed to be ultimativly fast and absolutely memory efficient, +but was written to fulfill this aspects to a certain level, real benchmarks still need to be done, the implementation can really well compete with famous implementations such as PCL(FLANN),ANN, and CGAL ) -The KdTree splitting heuristic implements an extendable sophisticated splitting optimization -which in the most elaborate, performance worst case consists of -searching for the best split between the splitting heuristics ``MIDPOINT`` , ``MEDIAN`` and ``GEOMETRIC_MEAN`` -by evaluating a user-provided quality evaluator. The simple standard quality evaluator is the ``LinearQualityEvaluator`` which computes the split quality by a weighted linear combination of the quantities ``splitRatio`` , ``pointRatio``, ``minMaxExtentRatio``. +The KdTree splitting heuristic implements an extendable sophisticated splitting optimization +which in the most elaborate, performance worst case consists of +searching for the best split between the splitting heuristics `MIDPOINT` , `MEDIAN` and `GEOMETRIC_MEAN` +by evaluating a user-provided quality evaluator. The simple standard quality evaluator is the `LinearQualityEvaluator` which computes the split quality by a weighted linear combination of the quantities `splitRatio` , `pointRatio`, `minMaxExtentRatio`. Outlier filtering is done with the k-nearest neighbor search algorithm (similar to the PCL library but faster, and with user defined precision) and works roughly as the following: -The algorithm finds for each point ``p`` in the point cloud ``k`` nearest neighbors and averages their distance (distance functor) to the point ``p`` -to obtain a mean distance ``distance`` for this particular point. -All nearest mean distances for all points give a histogram with a sample mean ``mean`` and sample standard deviation ``stdDev``. -All points which have a mean nearest neighbor distance greater or equal to ``mean + stdDevMult * stdDev`` +The algorithm finds for each point `p` in the point cloud `k` nearest neighbors and averages their distance (distance functor) to the point `p` +to obtain a mean distance `distance` for this particular point. +All nearest mean distances for all points give a histogram with a sample mean `mean` and sample standard deviation `stdDev`. +All points which have a mean nearest neighbor distance greater or equal to `mean + stdDevMult * stdDev` are classified as outlier points. -Look at the examples in ``examples/kdTreeFiltering`` which produced the following pictures with the provided visualization notebook -``examples/kdTreeFiltering/python/VisualizeKdTree.ipynb``. +Look at the examples in `examples/kdTreeFiltering` which produced the following pictures with the provided visualization notebook +`examples/kdTreeFiltering/python/VisualizeKdTree.ipynb`.

-**Function Parameters & How It Works** +**Function Parameters & How It Works** To come ---------------------------- -Building and Visualizing the Tests ---------------------------- +--- + +## Building and Visualizing the Tests + Building and installing the basic tests is done by: ```bash cd ApproxMVBB - git submodule init + git submodule init git submodule update cd ../Build make build_and_test ``` -**Note that if the tests fail, submit a new issue and report which test failed. +**Note that if the tests fail, submit a new issue and report which test failed. The results can still be visualized and should be correct. ** - **Note:** -To run the test in high-performance mode (needs lots of ram), which tests also points clouds of -140 million points and some polygonal statue ``lucy.txt`` successfully you need -to set the cmake variable ``ApproxMVBB_TESTS_HIGH_PERFORMANCE`` to ``ON`` -and additionally initialize the submodule ``additional`` and unzip the files: +To run the test in high-performance mode (needs lots of ram), which tests also points clouds of +140 million points and some polygonal statue `lucy.txt` successfully you need +to set the cmake variable `ApproxMVBB_TESTS_HIGH_PERFORMANCE` to `ON` +and additionally initialize the submodule `additional` and unzip the files: + ```bash cd ApproxMVBB git submodule init git submodule update - cd additional/tests/files; cat Lucy* | tar xz + cd additional/tests/files; cat Lucy* | tar xz ``` -and rebuild the tests. (this will copy the additional files next to the executable) +and rebuild the tests. (this will copy the additional files next to the executable) -Executing the test application ``cd tests; ./ApproxMVBBTests`` will then run the following tests: +Executing the test application `cd tests; ./ApproxMVBBTests` will then run the following tests: 1. Testing the ConvexHull2D for several point clouds in 2D 2. Minimal area rectangle tests for several point clouds in 2D -3. Testing the diameter computation and calculation of the initial bounding box ``A`` +3. Testing the diameter computation and calculation of the initial bounding box `A` (see [section](Function Parameters & How It Works)) for point clouds in 3D 4. Testing the full optimization pipeline to generate an approximation of the minimal volume bounding box -The output can be visualized with the ``ipython notebook`` ``/tests/python/PlotTestResults.ipynb``: +The output can be visualized with the `ipython notebook` `/tests/python/PlotTestResults.ipynb`: + ```bash cd Build/tests ipython noteboook ``` +

--------------------------- -Benchmark --------------------------- -Here are some short benchmarks (single core) from the tests folder: +--- + +## Benchmark -| Point Cloud | # Points | ~ CPU Time ``approximateMVBB``| -| ------------ | --------:| --------:| -| Standford Bunny | 35'945 | 0.91 s | -| Standford Lucy | 14'027'872 | 1.19 s | -| Unit Cube | 140'000'000 | 7.0 s | +Here are some short benchmarks (single core) from the tests folder: -``approximateMVBB`` runs ``approximateMVBBDiam`` and performs a grid search afterwards (here 5x5x5=25 directions with 5 optimization runs for each) +| Point Cloud | # Points | ~ CPU Time `approximateMVBB` | +| --------------- | ----------: | ---------------------------: | +| Standford Bunny | 35'945 | 0.91 s | +| Standford Lucy | 14'027'872 | 1.19 s | +| Unit Cube | 140'000'000 | 7.0 s | + +`approximateMVBB` runs `approximateMVBBDiam` and performs a grid search afterwards (here 5x5x5=25 directions with 5 optimization runs for each) It seems to take a long time for 140 million points. The most inefficient task is to get a good initial bounding box. This takes the most time as diameter computations are performed in 3d and then all points are projected in the found diameter direction in 3d and another diameter in the projected plane in 2d is computed. Afterwards the point cloud is sampled (not just random points, its done with a grid) and convex hull, minimal rectangle computations are performed over the grid directions. These algorithms could be made faster by exploiting the following things: -* Use an axis aligned bounding box as the initial bounding box for the grid search (not implemented yet) -* Parallelism for the projection -> (CUDA, threads) --------------------------- -Multithreading Support --------------------------- +- Use an axis aligned bounding box as the initial bounding box for the grid search (not implemented yet) +- Parallelism for the projection -> (CUDA, threads) + +--- + +## Multithreading Support + You can build the library with OpenMP (by default enabled) You can set the cmake cache variables `ApproxMVBB_OPENMP_USE_OPENMP=On` which will further enable `ApproxMVBB_OPENMP_USE_NTHREADS=On/Off`. -The variable `ApproxMVBB_OPENMP_USE_NTHREADS` toogles the number of threads to use. -If `Off`, the number of threads is determined at runtime (default). +The variable `ApproxMVBB_OPENMP_USE_NTHREADS` toogles the number of threads to use. +If `Off`, the number of threads is determined at runtime (default). If you use clang, make sure you have the [OpenMP enabled clang](https://clang-omp.github.io/)! GCC already supports OpenMP. --------------------------- -References --------------------------- +--- + +## References + The main articles this code is based on: -``` + +```bibtex @Article{malandain2002, Author = {Gr'egoire Malandain and Jean-Daniel Boissonnat}, Journal = {International Journal of Computational Geometry & Applications}, @@ -311,8 +344,10 @@ Title = {Computing the Diameter of a Point Set}, Volume = {12}, Year = {2002}} ``` + and -``` + +```bibtex @inproceedings{barequet2001, Author = {Gill Barequet and Sariel Har-peled}, Booktitle = {In Proc. 10th ACM-SIAM Sympos. Discrete Algorithms}, @@ -323,7 +358,8 @@ Year = {2001}} ``` Optimizations for future work: -```cpp + +```bibtex @Article{chang2011, Acmid = {2019641}, Address = {New York, NY, USA}, @@ -348,18 +384,18 @@ Bdsk-Url-1 = {http://doi.acm.org/10.1145/2019627.2019641}, Bdsk-Url-2 = {http://dx.doi.org/10.1145/2019627.2019641}} ``` --------------------------- -Licensing --------------------------- +--- + +## Licensing + +This source code is released under MPL 2.0. -This source code is released under MPL 2.0. +--- ---------------------------- -Author and Acknowledgements ---------------------------- +## Author and Acknowledgements -ApproxMVBB was written by Gabriel Nützi, with source code from [Grégoire Malandain & Jean-Daniel Boissonnat](http://www-sop.inria.fr/members/Gregoire.Malandain/diameter/) +ApproxMVBB was written by Gabriel Nützi, with source code from [Grégoire Malandain & Jean-Daniel Boissonnat](http://www-sop.inria.fr/members/Gregoire.Malandain/diameter/) for the approximation of the diameter of a point cloud. I was inspired by the work and algorithms of [Gill Barequet & Sariel Har-Peled](http://sarielhp.org/p/98/bbox/) for computing a minimal volume bounding box. -Additionally, the geometric predicates (orient2d) used in the convex hull algorithm (graham scan) have been taken from the fine work of [Jonathan Richard Shewchuk](http://www.cs.cmu.edu/~quake/robust.html). +Additionally, the geometric predicates (orient2d) used in the convex hull algorithm (graham scan) have been taken from the fine work of [Jonathan Richard Shewchuk](http://www.cs.cmu.edu/~quake/robust.html). Special thanks go to my significant other which always had an ear during breakfast for this little project :kissing_heart: diff --git a/cmake/FindEigen3.cmake b/cmake/FindEigen3.cmake deleted file mode 100644 index f4a828d0..00000000 --- a/cmake/FindEigen3.cmake +++ /dev/null @@ -1,83 +0,0 @@ -# - Try to find Eigen3 lib -# -# This module supports requiring a minimum version, e.g. you can do -# find_package(Eigen3 3.1.2) -# to require version 3.1.2 or newer of Eigen3. -# -# Once done this will define -# -# EIGEN3_FOUND - system has eigen lib with correct version -# EIGEN3_INCLUDE_DIR - the eigen include directory -# EIGEN3_VERSION - eigen version - -# Copyright (c) 2006, 2007 Montel Laurent, -# Copyright (c) 2008, 2009 Gael Guennebaud, -# Copyright (c) 2009 Benoit Jacob -# Redistribution and use is allowed according to the terms of the 2-clause BSD license. - -if(NOT Eigen3_FIND_VERSION) - if(NOT Eigen3_FIND_VERSION_MAJOR) - set(Eigen3_FIND_VERSION_MAJOR 2) - endif(NOT Eigen3_FIND_VERSION_MAJOR) - if(NOT Eigen3_FIND_VERSION_MINOR) - set(Eigen3_FIND_VERSION_MINOR 91) - endif(NOT Eigen3_FIND_VERSION_MINOR) - if(NOT Eigen3_FIND_VERSION_PATCH) - set(Eigen3_FIND_VERSION_PATCH 0) - endif(NOT Eigen3_FIND_VERSION_PATCH) - - set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") -endif(NOT Eigen3_FIND_VERSION) - -macro(_eigen3_check_version) - file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) - - string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") - set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") - string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") - set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") - string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") - set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") - - set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) - if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - set(EIGEN3_VERSION_OK FALSE) - else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - set(EIGEN3_VERSION_OK TRUE) - endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - - if(NOT EIGEN3_VERSION_OK) - - message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " - "but at least version ${Eigen3_FIND_VERSION} is required") - endif(NOT EIGEN3_VERSION_OK) -endmacro(_eigen3_check_version) - -if (EIGEN3_INCLUDE_DIR) - - # in cache already - _eigen3_check_version() - set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) - -else (EIGEN3_INCLUDE_DIR) - - find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library - PATHS - ${CMAKE_INSTALL_PREFIX}/include - $ENV{EIGEN_HOME} - $ENV{EIGEN_ROOT} - ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES eigen3 eigen - ) - - if(EIGEN3_INCLUDE_DIR) - _eigen3_check_version() - endif(EIGEN3_INCLUDE_DIR) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) - - mark_as_advanced(EIGEN3_INCLUDE_DIR) - -endif(EIGEN3_INCLUDE_DIR) - diff --git a/example/approxMVBB/CMakeLists.txt b/example/approxMVBB/CMakeLists.txt index f363c34a..f8c5f0c8 100644 --- a/example/approxMVBB/CMakeLists.txt +++ b/example/approxMVBB/CMakeLists.txt @@ -1,4 +1,6 @@ project("ApproxMVBBExample-MVBB") add_executable(${PROJECT_NAME} src/main.cpp ) +setTargetCompileOptions(ApproxMVBBExample-MVBB) + target_link_libraries(${PROJECT_NAME} "ApproxMVBB::Core") diff --git a/example/kdTreeFiltering/CMakeLists.txt b/example/kdTreeFiltering/CMakeLists.txt index 59cee92a..ab4d70e7 100644 --- a/example/kdTreeFiltering/CMakeLists.txt +++ b/example/kdTreeFiltering/CMakeLists.txt @@ -7,6 +7,8 @@ set(INCLUDE_DIRS add_executable(ApproxMVBBExample-KdTree ${SOURCE_FILES} ${INCLUDE_FILES} ) +setTargetCompileOptions(ApproxMVBBExample-KdTree) + # Link with Core, and add KDTreeSupport target_link_libraries(ApproxMVBBExample-KdTree ApproxMVBB::Core ApproxMVBB::KdTreeSupport) diff --git a/example/kdTreeFiltering/src/main.cpp b/example/kdTreeFiltering/src/main.cpp index be321dc2..e277a7dc 100644 --- a/example/kdTreeFiltering/src/main.cpp +++ b/example/kdTreeFiltering/src/main.cpp @@ -16,7 +16,7 @@ #include "ApproxMVBB/Common/CPUTimer.hpp" #include "ApproxMVBB/KdTree.hpp" -#ifdef ApproxMVBB_XMLSUPPORT +#ifdef ApproxMVBB_XML_SUPPORT # include "ApproxMVBB/KdTreeXml.hpp" #endif @@ -128,7 +128,7 @@ void doKdTree(std::string file) // auto list = tree.buildLeafNeighboursAutomatic(); std::cout << tree.getStatisticsString() << std::endl; -#ifdef ApproxMVBB_XMLSUPPORT +#ifdef ApproxMVBB_XML_SUPPORT std::string file = "KdTreeResults.xml"; std::cout << "Saving KdTree XML to: " << file << std::endl; diff --git a/example/libraryUsage/CMakeLists.txt b/example/libraryUsage/CMakeLists.txt index 1dd4cf2e..dc6fa06d 100644 --- a/example/libraryUsage/CMakeLists.txt +++ b/example/libraryUsage/CMakeLists.txt @@ -7,10 +7,11 @@ project(libraryUsage) get_filename_component( ApproxMVBB_DIR ${ApproxMVBB_DIR} ABSOLUTE ) message(STATUS "ApproxMVBB_DIR:" ${ApproxMVBB_DIR}) -# add ApproxMVBB +# add ApproxMVBB find_package(ApproxMVBB REQUIRED COMPONENTS XML_SUPPORT KDTREE_SUPPORT) # add simple executable add_executable(libraryUsage ./main.cpp) +setTargetCompileOptions(libraryUsage) target_link_libraries(libraryUsage ApproxMVBB::Core) \ No newline at end of file diff --git a/external/Diameter/src/EstimateDiameter.cpp b/external/Diameter/src/EstimateDiameter.cpp index b180d917..0853a922 100644 --- a/external/Diameter/src/EstimateDiameter.cpp +++ b/external/Diameter/src/EstimateDiameter.cpp @@ -73,7 +73,6 @@ namespace ApproxMVBB int i, j, k, n; int index1, index2; - int suspicion_of_convex_hull = 0; // not used int fdn, ldn, idn; double epsilon = _epsilon_; @@ -141,7 +140,6 @@ namespace ApproxMVBB // fprintf( stdout, "...processing frth: remove %d points\n", l-newlast ); if(newlast == l) { - suspicion_of_convex_hull = 1; reduction_mode_of_diameter = 0; reduction_mode_of_dbleNorm = 0; } @@ -260,7 +258,6 @@ namespace ApproxMVBB // fprintf( stdout, "...processing diam: remove %d points\n", l-newlast ); if(newlast == l) { - suspicion_of_convex_hull = 1; reduction_mode_of_dbleNorm = 0; } l = newlast; @@ -474,7 +471,6 @@ namespace ApproxMVBB // fprintf( stdout, "...processing dbNR: remove %d points\n", l-newlast ); if(newlast == l) { - suspicion_of_convex_hull = 1; for(k = 0; k < theDoubleNormals.n; k++) theDoubleNormals.seg[k].reduction_mode = 0; }