Repository: PJLab-ADG/Livox-Mapping
Branch: main
Commit: 38bc18f15ad8
Files: 73
Total size: 786.6 KB
Directory structure:
gitextract_r29jj8ts/
├── .gitignore
├── LICENSE
├── LIO-Livox/
│ ├── CMakeLists.txt
│ ├── LICENSE
│ ├── README.md
│ ├── cmake/
│ │ ├── FindEigen3.cmake
│ │ └── FindSuiteSparse.cmake
│ ├── config/
│ │ └── horizon_config.yaml
│ ├── include/
│ │ ├── Estimator/
│ │ │ └── Estimator.h
│ │ ├── IMUIntegrator/
│ │ │ └── IMUIntegrator.h
│ │ ├── LidarFeatureExtractor/
│ │ │ └── LidarFeatureExtractor.h
│ │ ├── MapManager/
│ │ │ └── Map_Manager.h
│ │ ├── segment/
│ │ │ ├── pointsCorrect.hpp
│ │ │ └── segment.hpp
│ │ ├── sophus/
│ │ │ ├── average.hpp
│ │ │ ├── common.hpp
│ │ │ ├── example_ensure_handler.cpp
│ │ │ ├── formatstring.hpp
│ │ │ ├── geometry.hpp
│ │ │ ├── interpolate.hpp
│ │ │ ├── interpolate_details.hpp
│ │ │ ├── num_diff.hpp
│ │ │ ├── rotation_matrix.hpp
│ │ │ ├── rxso2.hpp
│ │ │ ├── rxso3.hpp
│ │ │ ├── se2.hpp
│ │ │ ├── se3.hpp
│ │ │ ├── sim2.hpp
│ │ │ ├── sim3.hpp
│ │ │ ├── sim_details.hpp
│ │ │ ├── so2.hpp
│ │ │ ├── so3.hpp
│ │ │ ├── test_macros.hpp
│ │ │ ├── types.hpp
│ │ │ └── velocities.hpp
│ │ └── utils/
│ │ ├── ceresfunc.h
│ │ ├── math_utils.hpp
│ │ └── pcl_utils.hpp
│ ├── launch/
│ │ └── livox_odometry.launch
│ ├── package.xml
│ ├── rviz_cfg/
│ │ └── lio.rviz
│ └── src/
│ ├── lio/
│ │ ├── Estimator.cpp
│ │ ├── IMUIntegrator.cpp
│ │ ├── LidarFeatureExtractor.cpp
│ │ ├── Map_Manager.cpp
│ │ ├── PoseEstimation.cpp
│ │ ├── ScanRegistration.cpp
│ │ └── ceresfunc.cpp
│ └── segment/
│ ├── pointsCorrect.cpp
│ └── segment.cpp
├── README.md
├── SC-PGO/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── include/
│ │ ├── livox_mapping/
│ │ │ ├── common.h
│ │ │ └── tic_toc.h
│ │ └── scancontext/
│ │ ├── KDTreeVectorOfVectorsAdaptor.h
│ │ ├── Scancontext.cpp
│ │ ├── Scancontext.h
│ │ └── nanoflann.hpp
│ ├── launch/
│ │ └── livox_mapping.launch
│ ├── package.xml
│ ├── rviz_cfg/
│ │ └── livox_mapping.rviz
│ ├── src/
│ │ └── laserPosegraphOptimization.cpp
│ └── utils/
│ ├── moving_object_removal/
│ │ ├── README.md
│ │ └── move_object_removal_livox.py
│ └── python/
│ ├── bone_table.npy
│ ├── jet_table.npy
│ ├── makeMergedMap.py
│ └── pypcdMyUtils.py
└── ad_localization_msgs/
├── CMakeLists.txt
├── msg/
│ └── NavStateInfo.msg
└── package.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.vscode/
__pycache__/
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2021, PJLab-ADG
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: LIO-Livox/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 2.8.3)
project(livox_odometry)
SET(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "-std=c++11")
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
find_package(catkin REQUIRED COMPONENTS
message_generation
geometry_msgs
nav_msgs
sensor_msgs
roscpp
rospy
std_msgs
tf
tf_conversions
rosbag
livox_ros_driver
eigen_conversions
pcl_conversions
pcl_ros
message_filters
std_srvs)
find_package(Eigen3 REQUIRED)
find_package(PCL REQUIRED)
find_package(Ceres REQUIRED)
find_package(OpenCV REQUIRED)
find_package(SuiteSparse REQUIRED)
include_directories(include
${catkin_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIR}
${PCL_INCLUDE_DIRS}
${CERES_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${SUITESPARSE_INCLUDE_DIRS})
##################
## ROS messages ##
##################
generate_messages(DEPENDENCIES std_msgs)
catkin_package(CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy std_msgs message_runtime
pcl_conversions pcl_ros message_filters std_srvs tf_conversions tf
eigen_conversions DEPENDS PCL OpenCV INCLUDE_DIRS include)
add_executable (ScanRegistration
src/lio/ScanRegistration.cpp
src/lio/LidarFeatureExtractor.cpp
src/segment/segment.cpp
src/segment/pointsCorrect.cpp)
target_link_libraries(ScanRegistration ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${OpenCV_LIBRARIES})
add_executable (PoseEstimation
src/lio/PoseEstimation.cpp
src/lio/Estimator.cpp
src/lio/IMUIntegrator.cpp
src/lio/ceresfunc.cpp
src/lio/Map_Manager.cpp)
target_link_libraries(PoseEstimation ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${CERES_LIBRARIES})
================================================
FILE: LIO-Livox/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2021, LIVOX
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: LIO-Livox/README.md
================================================
# LIO-Livox (A Robust LiDAR-Inertial Odometry for Livox LiDAR)
This respository implements a robust LiDAR-inertial odometry system for Livox LiDAR.
The system uses only a single Livox LiDAR with a built-in IMU. It has a robust initialization module,
which is independent to the sensor motion. **It can be initialized with the static state, dynamic state, and the mixture of static and dynamic state.**
The system achieves super robust performance. **It can pass through a 4km-tunnel and run on the highway with a very high speed (about 80km/h) using a single Livox Horizon.**
Moreover, **it is also robust to dynamic objects**, such as cars, bicycles, and pedestrains. It obtains high precision of localization even in traffic jams.
**The mapping result is precise even most of the FOV is occluded by vehicles.**
Videos of the demonstration of the system can be found on Youtube and Bilibili. *NOTE: Images are only used for demonstration, not used in the system.*
**Developer**: [Livox](www.livoxtech.com)
## System achritecture
The system consists of two ros nodes: ScanRegistartion and PoseEstimation.
* The class "LidarFeatureExtractor" of the node "ScanRegistartion" extracts corner features, surface features, and irregular features from the raw point cloud.
* In the node "PoseEstimation", the main thread aims to estimate sensor poses, while another thread in the class "Estimator" uses the class "MapManager" to build and manage feature maps.
The system is mainly designed for car platforms in the large scale outdoor environment.
Users can easily run the system with a Livox Horizon LiDAR.Horizon
The system starts with the node "ScanRegistartion", where feature points are extracted. Before the feature extraction, dynamic objects are removed from the raw point cloud, since in urban scenes there are usually many dynamic objects, which
affect system robustness and precision. For the dynamic objects filter, we use a fast point cloud segmentation method. The Euclidean clustering is applied to group points into some clusters. The raw point cloud is divided into ground points, background points, and foreground points.
Foreground points are considered as dynamic objects, which are excluded form the feature extraction process. Due to the dynamic objects filter, the system obtains high robustness in dynamic scenes.
In open scenarios, usually few features can be extracted, leading to degeneracy on certain degrees of freedom. To tackle this problem, we developed a feature extraction process to make the distribution of feature points wide and uniform.
A uniform and wide distribution provides more constraints on all 6 degrees of freedom, which is helpful for eliminating degeneracy. Besides, some irregular points also provides information in feature-less
scenes. Therefore, we also extract irregular features as a class for the point cloud registration.
Feature points are classifed into three types, corner features, surface features, and irregular features, according to their
local geometry properties. We first extract points with large curvature and isolated points on each scan line as corner points. Then principal components analysis (PCA) is performed to classify surface features and irregular features, as shown in the following figure.
For points with different distance, thresholds are set to different values, in order to make the distribution of points in space as uniform as possible.
In the node "PoseEstimation", the motion distortion of the point cloud is compensated using IMU preintegration or constant velocity model. Then the IMU initialization module is performed. If the Initialization
is successfully finished, the system will switch to the LIO mode. Otherwise, it run with LO mode and initialize IMU states. In the LO mode, we use a frame-to-model point cloud registration to estimate the sensor pose.
Inspired by ORB-SLAM3, a maximum a posteriori (MAP) estimation method is adopted to jointly initialize IMU biases, velocities, and the gravity direction.
This method doesn't need a careful initialization process. **The system can be initialized with an arbitrary motion.** This method takes into account sensor uncertainty, which obtains the optimum in the sense of maximum posterior probability.
It achieves efficient, robust, and accurate performance.
After the initialization, a tightly coupled slding window based sensor fusion module is performed to estimate IMU poses, biases, and velocities within the sliding window.
Simultaneously, an extra thread builds and maintains the global map in parallel.
## Prerequisites
* [Ubuntu](http://ubuntu.com) (tested on 16.04 and 18.04)
* [ROS](http://wiki.ros.org/ROS/Installation) (tested with Kinetic and Melodic)
* [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page)
* [Ceres Solver](http://ceres-solver.org/installation.html)
* [PCL](http://www.pointclouds.org/downloads/linux.html)
* [livox_ros_driver](https://github.com/Livox-SDK/livox_ros_driver)
* Suitesparse
```
sudo apt-get install libsuitesparse-dev
```
## Compilation
```
cd ~/catkin_ws/src
git clone https://github.com/Livox-SDK/LIO-Livox
cd ..
catkin_make
```
## Run with bag files:
### Run the launch file:
```
cd ~/catkin_ws
source devel/setup.bash
roslaunch lio_livox horizon.launch
```
#### Play your bag files:
```
rosbag play YOUR_ROSBAG.bag
```
## Run with your device:
### Run your LiDAR with livox_ros_driver
```
cd ~/catkin_ws
source devel/setup.bash
roslaunch livox_ros_driver livox_lidar_msg.launch
```
### Run the launch file:
```
cd ~/catkin_ws
source devel/setup.bash
roslaunch lio_livox horizon.launch
```
## Notes:
The current version of the system is only adopted for Livox Horizon. In theory, it should be able to run directly with a Livox Avia, but we haven't done enough tests.
Besides, the system doesn't provide a interface of Livox mid series. If you want use mid-40 or mid-70, you can try [livox_mapping](https://github.com/Livox-SDK/livox_mapping).
The topic of point cloud messages is /livox/lidar and its type is livox_ros_driver/CustomMsg. \
The topic of IMU messages is /livox/imu and its type is sensor_msgs/Imu.
There are some parameters in launch files:
* IMU_Mode: choose IMU information fusion strategy, there are 3 modes:
- 0 - without using IMU information, pure LiDAR odometry, motion distortion is removed using a constant velocity model
- 1 - using IMU preintegration to remove motion distortion
- 2 - tightly coupling IMU and LiDAR information
* Extrinsic_Tlb: extrinsic parameter between LiDAR and IMU, which uses SE3 form. If you want to use an external IMU, you need to calibrate your own sensor suite
and change this parameter to your extrinsic parameter.
There are also some parameters in the config file:
* Use_seg: choose the segmentation mode for dynamic objects filtering, there are 2 modes:
- 0 - without using the segmentation method, you can choose this mode if there is few dynamic objects in your data
- 1 - using the segmentation method to remove dynamic objects
## Acknowledgements
Thanks for following work:
* [LOAM](https://github.com/cuitaixiang/LOAM_NOTED) (LOAM: Lidar Odometry and Mapping in Real-time)
* [VINS-Mono](https://github.com/HKUST-Aerial-Robotics/VINS-Mono) (VINS-Mono: A Robust and Versatile Monocular Visual-Inertial State Estimator)
* [LIO-mapping](https://github.com/hyye/lio-mapping) (Tightly Coupled 3D Lidar Inertial Odometry and Mapping)
* [ORB-SLAM3](https://github.com/UZ-SLAMLab/ORB_SLAM3) (ORB-SLAM3: An Accurate Open-Source Library for Visual, Visual-Inertial and Multi-Map SLAM)
* [LiLi-OM](https://github.com/KIT-ISAS/lili-om) (Towards High-Performance Solid-State-LiDAR-Inertial Odometry and Mapping)
* [MSCKF_VIO](https://github.com/KumarRobotics/msckf_vio) (Robust Stereo Visual Inertial Odometry for Fast Autonomous Flight)
* [horizon_highway_slam](https://github.com/Livox-SDK/horizon_highway_slam)
* [livox_mapping](https://github.com/Livox-SDK/livox_mapping)
* [livox_horizon_loam](https://github.com/Livox-SDK/livox_horizon_loam)
## Support
You can get support from Livox with the following methods:
* Send email to [cs@livoxtech.com](cs@livoxtech.com) with a clear description of your problem and your setup
* Report issues on github
================================================
FILE: LIO-Livox/cmake/FindEigen3.cmake
================================================
# - 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)
# specific additional paths for some OS
if (WIN32)
set(EIGEN_ADDITIONAL_SEARCH_PATHS ${EIGEN_ADDITIONAL_SEARCH_PATHS} "C:/Program Files/Eigen/include" "C:/Program Files (x86)/Eigen/include")
endif(WIN32)
find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
PATHS
${CMAKE_INSTALL_PREFIX}/include
${EIGEN_ADDITIONAL_SEARCH_PATHS}
${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)
================================================
FILE: LIO-Livox/cmake/FindSuiteSparse.cmake
================================================
# Ceres Solver - A fast non-linear least squares minimizer
# Copyright 2015 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Google Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: alexs.mac@gmail.com (Alex Stewart)
#
# FindSuiteSparse.cmake - Find SuiteSparse libraries & dependencies.
#
# This module defines the following variables:
#
# SUITESPARSE_FOUND: TRUE iff SuiteSparse and all dependencies have been found.
# SUITESPARSE_INCLUDE_DIRS: Include directories for all SuiteSparse components.
# SUITESPARSE_LIBRARIES: Libraries for all SuiteSparse component libraries and
# dependencies.
# SUITESPARSE_VERSION: Extracted from UFconfig.h (<= v3) or
# SuiteSparse_config.h (>= v4).
# SUITESPARSE_MAIN_VERSION: Equal to 4 if SUITESPARSE_VERSION = 4.2.1
# SUITESPARSE_SUB_VERSION: Equal to 2 if SUITESPARSE_VERSION = 4.2.1
# SUITESPARSE_SUBSUB_VERSION: Equal to 1 if SUITESPARSE_VERSION = 4.2.1
#
# SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION: TRUE iff running
# on Ubuntu, SUITESPARSE_VERSION is 3.4.0 and found SuiteSparse is a system
# install, in which case found version of SuiteSparse cannot be used to link
# a shared library due to a bug (static linking is unaffected).
#
# The following variables control the behaviour of this module:
#
# SUITESPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to
# search for SuiteSparse includes,
# e.g: /timbuktu/include.
# SUITESPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to
# search for SuiteSparse libraries,
# e.g: /timbuktu/lib.
#
# The following variables define the presence / includes & libraries for the
# SuiteSparse components searched for, the SUITESPARSE_XX variables are the
# union of the variables for all components.
#
# == Symmetric Approximate Minimum Degree (AMD)
# AMD_FOUND
# AMD_INCLUDE_DIR
# AMD_LIBRARY
#
# == Constrained Approximate Minimum Degree (CAMD)
# CAMD_FOUND
# CAMD_INCLUDE_DIR
# CAMD_LIBRARY
#
# == Column Approximate Minimum Degree (COLAMD)
# COLAMD_FOUND
# COLAMD_INCLUDE_DIR
# COLAMD_LIBRARY
#
# Constrained Column Approximate Minimum Degree (CCOLAMD)
# CCOLAMD_FOUND
# CCOLAMD_INCLUDE_DIR
# CCOLAMD_LIBRARY
#
# == Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
# CHOLMOD_FOUND
# CHOLMOD_INCLUDE_DIR
# CHOLMOD_LIBRARY
#
# == Multifrontal Sparse QR (SuiteSparseQR)
# SUITESPARSEQR_FOUND
# SUITESPARSEQR_INCLUDE_DIR
# SUITESPARSEQR_LIBRARY
#
# == Common configuration for all but CSparse (SuiteSparse version >= 4).
# SUITESPARSE_CONFIG_FOUND
# SUITESPARSE_CONFIG_INCLUDE_DIR
# SUITESPARSE_CONFIG_LIBRARY
#
# == Common configuration for all but CSparse (SuiteSparse version < 4).
# UFCONFIG_FOUND
# UFCONFIG_INCLUDE_DIR
#
# Optional SuiteSparse Dependencies:
#
# == Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
# METIS_FOUND
# METIS_LIBRARY
#
# == Intel Thread Building Blocks (TBB)
# TBB_FOUND
# TBB_LIBRARY
# TBB_MALLOC_FOUND
# TBB_MALLOC_LIBRARY
# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
# FindSuiteSparse was invoked.
macro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
if (MSVC)
set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
endif (MSVC)
endmacro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
# Called if we failed to find SuiteSparse or any of it's required dependencies,
# unsets all public (designed to be used externally) variables and reports
# error message at priority depending upon [REQUIRED/QUIET/] argument.
macro(SUITESPARSE_REPORT_NOT_FOUND REASON_MSG)
unset(SUITESPARSE_FOUND)
unset(SUITESPARSE_INCLUDE_DIRS)
unset(SUITESPARSE_LIBRARIES)
unset(SUITESPARSE_VERSION)
unset(SUITESPARSE_MAIN_VERSION)
unset(SUITESPARSE_SUB_VERSION)
unset(SUITESPARSE_SUBSUB_VERSION)
# Do NOT unset SUITESPARSE_FOUND_REQUIRED_VARS here, as it is used by
# FindPackageHandleStandardArgs() to generate the automatic error message on
# failure which highlights which components are missing.
suitesparse_reset_find_library_prefix()
# Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
# use the camelcase library name, not uppercase.
if (SuiteSparse_FIND_QUIETLY)
message(STATUS "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
elseif (SuiteSparse_FIND_REQUIRED)
message(FATAL_ERROR "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
else()
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
# but continues configuration and allows generation.
message("-- Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
endif (SuiteSparse_FIND_QUIETLY)
# Do not call return(), s/t we keep processing if not called with REQUIRED
# and report all missing components, rather than bailing after failing to find
# the first.
endmacro(SUITESPARSE_REPORT_NOT_FOUND)
# Protect against any alternative find_package scripts for this library having
# been called previously (in a client project) which set SUITESPARSE_FOUND, but
# not the other variables we require / set here which could cause the search
# logic here to fail.
unset(SUITESPARSE_FOUND)
# Handle possible presence of lib prefix for libraries on MSVC, see
# also SUITESPARSE_RESET_FIND_LIBRARY_PREFIX().
if (MSVC)
# Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
# s/t we can set it back before returning.
set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
# The empty string in this list is important, it represents the case when
# the libraries have no prefix (shared libraries / DLLs).
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
endif (MSVC)
# Specify search directories for include files and libraries (this is the union
# of the search directories for all OSs). Search user-specified hint
# directories first if supplied, and search user-installed locations first
# so that we prefer user installs to system installs where both exist.
list(APPEND SUITESPARSE_CHECK_INCLUDE_DIRS
/opt/local/include
/opt/local/include/ufsparse # Mac OS X
/usr/local/homebrew/include # Mac OS X
/usr/local/include
/usr/include)
list(APPEND SUITESPARSE_CHECK_LIBRARY_DIRS
/opt/local/lib
/opt/local/lib/ufsparse # Mac OS X
/usr/local/homebrew/lib # Mac OS X
/usr/local/lib
/usr/lib)
# Additional suffixes to try appending to each search path.
list(APPEND SUITESPARSE_CHECK_PATH_SUFFIXES
suitesparse) # Windows/Ubuntu
# Wrappers to find_path/library that pass the SuiteSparse search hints/paths.
#
# suitesparse_find_component( [FILES name1 [name2 ...]]
# [LIBRARIES name1 [name2 ...]]
# [REQUIRED])
macro(suitesparse_find_component COMPONENT)
include(CMakeParseArguments)
set(OPTIONS REQUIRED)
set(MULTI_VALUE_ARGS FILES LIBRARIES)
cmake_parse_arguments(SUITESPARSE_FIND_${COMPONENT}
"${OPTIONS}" "" "${MULTI_VALUE_ARGS}" ${ARGN})
if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS ${COMPONENT}_FOUND)
endif()
set(${COMPONENT}_FOUND TRUE)
if (SUITESPARSE_FIND_${COMPONENT}_FILES)
find_path(${COMPONENT}_INCLUDE_DIR
NAMES ${SUITESPARSE_FIND_${COMPONENT}_FILES}
HINTS ${SUITESPARSE_INCLUDE_DIR_HINTS}
PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}
PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
if (${COMPONENT}_INCLUDE_DIR)
message(STATUS "Found ${COMPONENT} headers in: "
"${${COMPONENT}_INCLUDE_DIR}")
mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
else()
# Specified headers not found.
set(${COMPONENT}_FOUND FALSE)
if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
suitesparse_report_not_found(
"Did not find ${COMPONENT} header (required SuiteSparse component).")
else()
message(STATUS "Did not find ${COMPONENT} header (optional "
"SuiteSparse component).")
# Hide optional vars from CMake GUI even if not found.
mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
endif()
endif()
endif()
if (SUITESPARSE_FIND_${COMPONENT}_LIBRARIES)
find_library(${COMPONENT}_LIBRARY
NAMES ${SUITESPARSE_FIND_${COMPONENT}_LIBRARIES}
HINTS ${SUITESPARSE_LIBRARY_DIR_HINTS}
PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}
PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
if (${COMPONENT}_LIBRARY)
message(STATUS "Found ${COMPONENT} library: ${${COMPONENT}_LIBRARY}")
mark_as_advanced(${COMPONENT}_LIBRARY)
else ()
# Specified libraries not found.
set(${COMPONENT}_FOUND FALSE)
if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
suitesparse_report_not_found(
"Did not find ${COMPONENT} library (required SuiteSparse component).")
else()
message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse "
"dependency)")
# Hide optional vars from CMake GUI even if not found.
mark_as_advanced(${COMPONENT}_LIBRARY)
endif()
endif()
endif()
endmacro()
# Given the number of components of SuiteSparse, and to ensure that the
# automatic failure message generated by FindPackageHandleStandardArgs()
# when not all required components are found is helpful, we maintain a list
# of all variables that must be defined for SuiteSparse to be considered found.
unset(SUITESPARSE_FOUND_REQUIRED_VARS)
# BLAS.
find_package(BLAS QUIET)
if (NOT BLAS_FOUND)
suitesparse_report_not_found(
"Did not find BLAS library (required for SuiteSparse).")
endif (NOT BLAS_FOUND)
list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS BLAS_FOUND)
# LAPACK.
find_package(LAPACK QUIET)
if (NOT LAPACK_FOUND)
suitesparse_report_not_found(
"Did not find LAPACK library (required for SuiteSparse).")
endif (NOT LAPACK_FOUND)
list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS LAPACK_FOUND)
suitesparse_find_component(AMD REQUIRED FILES amd.h LIBRARIES amd)
suitesparse_find_component(CAMD REQUIRED FILES camd.h LIBRARIES camd)
suitesparse_find_component(COLAMD REQUIRED FILES colamd.h LIBRARIES colamd)
suitesparse_find_component(CCOLAMD REQUIRED FILES ccolamd.h LIBRARIES ccolamd)
suitesparse_find_component(CHOLMOD REQUIRED FILES cholmod.h LIBRARIES cholmod)
suitesparse_find_component(
SUITESPARSEQR REQUIRED FILES SuiteSparseQR.hpp LIBRARIES spqr)
if (SUITESPARSEQR_FOUND)
# SuiteSparseQR may be compiled with Intel Threading Building Blocks,
# we assume that if TBB is installed, SuiteSparseQR was compiled with
# support for it, this will do no harm if it wasn't.
find_package(TBB QUIET)
if (TBB_FOUND)
message(STATUS "Found Intel Thread Building Blocks (TBB) library "
"(${TBB_VERSION}) assuming SuiteSparseQR was compiled "
"with TBB.")
# Add the TBB libraries to the SuiteSparseQR libraries (the only
# libraries to optionally depend on TBB).
list(APPEND SUITESPARSEQR_LIBRARY ${TBB_LIBRARIES})
else()
message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was "
"not compiled with TBB.")
endif()
endif(SUITESPARSEQR_FOUND)
# UFconfig / SuiteSparse_config.
#
# If SuiteSparse version is >= 4 then SuiteSparse_config is required.
# For SuiteSparse 3, UFconfig.h is required.
suitesparse_find_component(
SUITESPARSE_CONFIG FILES SuiteSparse_config.h LIBRARIES suitesparseconfig)
if (SUITESPARSE_CONFIG_FOUND)
# SuiteSparse_config (SuiteSparse version >= 4) requires librt library for
# timing by default when compiled on Linux or Unix, but not on OSX (which
# does not have librt).
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
suitesparse_find_component(LIBRT LIBRARIES rt)
if (LIBRT_FOUND)
message(STATUS "Adding librt: ${LIBRT_LIBRARY} to "
"SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
"SuiteSparse is compiled with timing).")
list(APPEND SUITESPARSE_CONFIG_LIBRARY ${LIBRT_LIBRARY})
else()
message(STATUS "Could not find librt, but found SuiteSparse_config, "
"assuming that SuiteSparse was compiled without timing.")
endif ()
endif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
else()
# Failed to find SuiteSparse_config (>= v4 installs), instead look for
# UFconfig header which should be present in < v4 installs.
suitesparse_find_component(UFCONFIG FILES UFconfig.h)
endif ()
if (NOT SUITESPARSE_CONFIG_FOUND AND
NOT UFCONFIG_FOUND)
suitesparse_report_not_found(
"Failed to find either: SuiteSparse_config header & library (should be "
"present in all SuiteSparse >= v4 installs), or UFconfig header (should "
"be present in all SuiteSparse < v4 installs).")
endif()
# Extract the SuiteSparse version from the appropriate header (UFconfig.h for
# <= v3, SuiteSparse_config.h for >= v4).
list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS SUITESPARSE_VERSION)
if (UFCONFIG_FOUND)
# SuiteSparse version <= 3.
set(SUITESPARSE_VERSION_FILE ${UFCONFIG_INCLUDE_DIR}/UFconfig.h)
if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
suitesparse_report_not_found(
"Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
"information for <= v3 SuiteSparse installs, but UFconfig was found "
"(only present in <= v3 installs).")
else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
file(READ ${SUITESPARSE_VERSION_FILE} UFCONFIG_CONTENTS)
string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
SUITESPARSE_MAIN_VERSION "${UFCONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
SUITESPARSE_SUB_VERSION "${UFCONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
SUITESPARSE_SUBSUB_VERSION "${UFCONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
# This is on a single line s/t CMake does not interpret it as a list of
# elements and insert ';' separators which would result in 4.;2.;1 nonsense.
set(SUITESPARSE_VERSION
"${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
endif (UFCONFIG_FOUND)
if (SUITESPARSE_CONFIG_FOUND)
# SuiteSparse version >= 4.
set(SUITESPARSE_VERSION_FILE
${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h)
if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
suitesparse_report_not_found(
"Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
"information for >= v4 SuiteSparse installs, but SuiteSparse_config was "
"found (only present in >= v4 installs).")
else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
file(READ ${SUITESPARSE_VERSION_FILE} SUITESPARSE_CONFIG_CONTENTS)
string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
SUITESPARSE_MAIN_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
SUITESPARSE_SUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
# This is on a single line s/t CMake does not interpret it as a list of
# elements and insert ';' separators which would result in 4.;2.;1 nonsense.
set(SUITESPARSE_VERSION
"${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
endif (SUITESPARSE_CONFIG_FOUND)
# METIS (Optional dependency).
suitesparse_find_component(METIS LIBRARIES metis)
# Only mark SuiteSparse as found if all required components and dependencies
# have been found.
set(SUITESPARSE_FOUND TRUE)
foreach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
if (NOT ${REQUIRED_VAR})
set(SUITESPARSE_FOUND FALSE)
endif (NOT ${REQUIRED_VAR})
endforeach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
if (SUITESPARSE_FOUND)
list(APPEND SUITESPARSE_INCLUDE_DIRS
${AMD_INCLUDE_DIR}
${CAMD_INCLUDE_DIR}
${COLAMD_INCLUDE_DIR}
${CCOLAMD_INCLUDE_DIR}
${CHOLMOD_INCLUDE_DIR}
${SUITESPARSEQR_INCLUDE_DIR})
# Handle config separately, as otherwise at least one of them will be set
# to NOTFOUND which would cause any check on SUITESPARSE_INCLUDE_DIRS to fail.
if (SUITESPARSE_CONFIG_FOUND)
list(APPEND SUITESPARSE_INCLUDE_DIRS
${SUITESPARSE_CONFIG_INCLUDE_DIR})
endif (SUITESPARSE_CONFIG_FOUND)
if (UFCONFIG_FOUND)
list(APPEND SUITESPARSE_INCLUDE_DIRS
${UFCONFIG_INCLUDE_DIR})
endif (UFCONFIG_FOUND)
# As SuiteSparse includes are often all in the same directory, remove any
# repetitions.
list(REMOVE_DUPLICATES SUITESPARSE_INCLUDE_DIRS)
# Important: The ordering of these libraries is *NOT* arbitrary, as these
# could potentially be static libraries their link ordering is important.
list(APPEND SUITESPARSE_LIBRARIES
${SUITESPARSEQR_LIBRARY}
${CHOLMOD_LIBRARY}
${CCOLAMD_LIBRARY}
${CAMD_LIBRARY}
${COLAMD_LIBRARY}
${AMD_LIBRARY}
${LAPACK_LIBRARIES}
${BLAS_LIBRARIES})
if (SUITESPARSE_CONFIG_FOUND)
list(APPEND SUITESPARSE_LIBRARIES
${SUITESPARSE_CONFIG_LIBRARY})
endif (SUITESPARSE_CONFIG_FOUND)
if (METIS_FOUND)
list(APPEND SUITESPARSE_LIBRARIES
${METIS_LIBRARY})
endif (METIS_FOUND)
endif()
# Determine if we are running on Ubuntu with the package install of SuiteSparse
# which is broken and does not support linking a shared library.
set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION FALSE)
if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
find_program(LSB_RELEASE_EXECUTABLE lsb_release)
if (LSB_RELEASE_EXECUTABLE)
# Any even moderately recent Ubuntu release (likely to be affected by
# this bug) should have lsb_release, if it isn't present we are likely
# on a different Linux distribution (should be fine).
execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -si
OUTPUT_VARIABLE LSB_DISTRIBUTOR_ID
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
# We are on Ubuntu, and the SuiteSparse version matches the broken
# system install version and is a system install.
set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION TRUE)
message(STATUS "Found system install of SuiteSparse "
"${SUITESPARSE_VERSION} running on Ubuntu, which has a known bug "
"preventing linking of shared libraries (static linking unaffected).")
endif (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
endif (LSB_RELEASE_EXECUTABLE)
endif (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
suitesparse_reset_find_library_prefix()
# Handle REQUIRED and QUIET arguments to FIND_PACKAGE
include(FindPackageHandleStandardArgs)
if (SUITESPARSE_FOUND)
find_package_handle_standard_args(SuiteSparse
REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
VERSION_VAR SUITESPARSE_VERSION
FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
else (SUITESPARSE_FOUND)
# Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to
# find SuiteSparse to avoid a confusing autogenerated failure message
# that states 'not found (missing: FOO) (found version: x.y.z)'.
find_package_handle_standard_args(SuiteSparse
REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
endif (SUITESPARSE_FOUND)
================================================
FILE: LIO-Livox/config/horizon_config.yaml
================================================
%YAML:1.0
# switches
Lidar_Type: 0 # 0-horizon
Used_Line: 6 # lines used for lio, set to 1~6
Feature_Mode: 0 # 0(false) or 1(true)
NumCurvSize: 2
DistanceFaraway: 100 # [m] DistanceFaraway far
NumFlat: 3 # nums of one part's flat feature
PartNum: 150 # nums of one scan's parts
FlatThreshold: 0.02 # cloud curvature threshold of flat feature
BreakCornerDis: 1 # break distance of break points
LidarNearestDis: 1.0 # if(depth < LidarNearestDis) do not use this point
KdTreeCornerOutlierDis: 0.2 # corner filter threshold
Use_seg: 1 # use segment algorithm
map_skip_frame: 2
================================================
FILE: LIO-Livox/include/Estimator/Estimator.h
================================================
#ifndef LIO_LIVOX_ESTIMATOR_H
#define LIO_LIVOX_ESTIMATOR_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "MapManager/Map_Manager.h"
#include "utils/ceresfunc.h"
#include "utils/pcl_utils.hpp"
#include "IMUIntegrator/IMUIntegrator.h"
#include
class Estimator{
typedef pcl::PointXYZINormal PointType;
public:
/** \brief slide window size */
static const int SLIDEWINDOWSIZE = 10;
/** \brief lidar frame struct */
struct LidarFrame{
pcl::PointCloud::Ptr laserCloud;
IMUIntegrator imuIntegrator;
Eigen::Vector3d P;
Eigen::Vector3d V;
Eigen::Quaterniond Q;
Eigen::Vector3d bg;
Eigen::Vector3d ba;
Eigen::VectorXf ground_plane_coeff;
double timeStamp;
LidarFrame(){
P.setZero();
V.setZero();
Q.setIdentity();
bg.setZero();
ba.setZero();
timeStamp = 0;
}
};
/** \brief point to line feature */
struct FeatureLine{
Eigen::Vector3d pointOri;
Eigen::Vector3d lineP1;
Eigen::Vector3d lineP2;
double error;
bool valid;
FeatureLine(Eigen::Vector3d po, Eigen::Vector3d p1, Eigen::Vector3d p2)
:pointOri(std::move(po)), lineP1(std::move(p1)), lineP2(std::move(p2)){
valid = false;
error = 0;
}
double ComputeError(const Eigen::Matrix4d& pose){
Eigen::Vector3d P_to_Map = pose.topLeftCorner(3,3) * pointOri + pose.topRightCorner(3,1);
double l12 = std::sqrt((lineP1(0) - lineP2(0))*(lineP1(0) - lineP2(0)) + (lineP1(1) - lineP2(1))*
(lineP1(1) - lineP2(1)) + (lineP1(2) - lineP2(2))*(lineP1(2) - lineP2(2)));
double a012 = std::sqrt(
((P_to_Map(0) - lineP1(0)) * (P_to_Map(1) - lineP2(1)) - (P_to_Map(0) - lineP2(0)) * (P_to_Map(1) - lineP1(1)))
* ((P_to_Map(0) - lineP1(0)) * (P_to_Map(1) - lineP2(1)) - (P_to_Map(0) - lineP2(0)) * (P_to_Map(1) - lineP1(1)))
+ ((P_to_Map(0) - lineP1(0)) * (P_to_Map(2) - lineP2(2)) - (P_to_Map(0) - lineP2(0)) * (P_to_Map(2) - lineP1(2)))
* ((P_to_Map(0) - lineP1(0)) * (P_to_Map(2) - lineP2(2)) - (P_to_Map(0) - lineP2(0)) * (P_to_Map(2) - lineP1(2)))
+ ((P_to_Map(1) - lineP1(1)) * (P_to_Map(2) - lineP2(2)) - (P_to_Map(1) - lineP2(1)) * (P_to_Map(2) - lineP1(2)))
* ((P_to_Map(1) - lineP1(1)) * (P_to_Map(2) - lineP2(2)) - (P_to_Map(1) - lineP2(1)) * (P_to_Map(2) - lineP1(2))));
error = a012 / l12;
}
};
/** \brief point to plan feature */
struct FeaturePlan{
Eigen::Vector3d pointOri;
double pa;
double pb;
double pc;
double pd;
double error;
bool valid;
FeaturePlan(const Eigen::Vector3d& po, const double& pa_, const double& pb_, const double& pc_, const double& pd_)
:pointOri(po), pa(pa_), pb(pb_), pc(pc_), pd(pd_){
valid = false;
error = 0;
}
double ComputeError(const Eigen::Matrix4d& pose){
Eigen::Vector3d P_to_Map = pose.topLeftCorner(3,3) * pointOri + pose.topRightCorner(3,1);
error = pa * P_to_Map(0) + pb * P_to_Map(1) + pc * P_to_Map(2) + pd;
}
};
/** \brief point to plan feature */
struct FeaturePlanVec{
Eigen::Vector3d pointOri;
Eigen::Vector3d pointProj;
Eigen::Matrix3d sqrt_info;
double error;
bool valid;
FeaturePlanVec(const Eigen::Vector3d& po, const Eigen::Vector3d& p_proj, Eigen::Matrix3d sqrt_info_)
:pointOri(po), pointProj(p_proj), sqrt_info(sqrt_info_) {
valid = false;
error = 0;
}
double ComputeError(const Eigen::Matrix4d& pose){
Eigen::Vector3d P_to_Map = pose.topLeftCorner(3,3) * pointOri + pose.topRightCorner(3,1);
error = (P_to_Map - pointProj).norm();
}
};
/** \brief non feature */
struct FeatureNon{
Eigen::Vector3d pointOri;
double pa;
double pb;
double pc;
double pd;
double error;
bool valid;
FeatureNon(const Eigen::Vector3d& po, const double& pa_, const double& pb_, const double& pc_, const double& pd_)
:pointOri(po), pa(pa_), pb(pb_), pc(pc_), pd(pd_){
valid = false;
error = 0;
}
double ComputeError(const Eigen::Matrix4d& pose){
Eigen::Vector3d P_to_Map = pose.topLeftCorner(3,3) * pointOri + pose.topRightCorner(3,1);
error = pa * P_to_Map(0) + pb * P_to_Map(1) + pc * P_to_Map(2) + pd;
}
};
public:
/** \brief constructor of Estimator
*/
Estimator(const float& filter_corner, const float& filter_surf);
~Estimator();
/** \brief Open a independent thread to increment MAP cloud
*/
[[noreturn]] void threadMapIncrement();
/** \brief construct sharp feature Ceres Costfunctions
* \param[in] edges: store costfunctions
* \param[in] m4d: lidar pose, represented by matrix 4X4
*/
void processPointToLine(std::vector& edges,
std::vector& vLineFeatures,
const pcl::PointCloud::Ptr& laserCloudCorner,
const pcl::PointCloud::Ptr& laserCloudCornerMap,
const pcl::KdTreeFLANN::Ptr& kdtree,
const Eigen::Matrix4d& exTlb,
const Eigen::Matrix4d& m4d);
/** \brief construct Plan feature Ceres Costfunctions
* \param[in] edges: store costfunctions
* \param[in] m4d: lidar pose, represented by matrix 4X4
*/
void processPointToPlan(std::vector& edges,
std::vector& vPlanFeatures,
const pcl::PointCloud::Ptr& laserCloudSurf,
const pcl::PointCloud::Ptr& laserCloudSurfMap,
const pcl::KdTreeFLANN::Ptr& kdtree,
const Eigen::Matrix4d& exTlb,
const Eigen::Matrix4d& m4d);
void processPointToPlanVec(std::vector& edges,
std::vector& vPlanFeatures,
const pcl::PointCloud::Ptr& laserCloudSurf,
const pcl::PointCloud::Ptr& laserCloudSurfMap,
const pcl::KdTreeFLANN::Ptr& kdtree,
const Eigen::Matrix4d& exTlb,
const Eigen::Matrix4d& m4d);
void processNonFeatureICP(std::vector& edges,
std::vector& vNonFeatures,
const pcl::PointCloud::Ptr& laserCloudNonFeature,
const pcl::PointCloud::Ptr& laserCloudNonFeatureLocal,
const pcl::KdTreeFLANN::Ptr& kdtreeLocal,
const Eigen::Matrix4d& exTlb,
const Eigen::Matrix4d& m4d);
/** \brief Transform Lidar Pose in slidewindow to double array
* \param[in] lidarFrameList: Lidar Poses in slidewindow
*/
void vector2double(const std::list& lidarFrameList);
/** \brief Transform double array to Lidar Pose in slidewindow
* \param[in] lidarFrameList: Lidar Poses in slidewindow
*/
void double2vector(std::list& lidarFrameList);
/** \brief estimate lidar pose by matching current lidar cloud with map cloud and tightly coupled IMU message
* \param[in] lidarFrameList: multi-frames of lidar cloud and lidar pose
* \param[in] exTlb: extrinsic matrix between lidar and IMU
* \param[in] gravity: gravity vector
*/
void EstimateLidarPose(std::list& lidarFrameList,
const Eigen::Matrix4d& exTlb,
const Eigen::Vector3d& gravity,
nav_msgs::Odometry& debugInfo);
void Estimate(std::list& lidarFrameList,
const Eigen::Matrix4d& exTlb,
const Eigen::Vector3d& gravity);
pcl::PointCloud::Ptr get_corner_map(){
return map_manager->get_corner_map();
}
pcl::PointCloud::Ptr get_surf_map(){
return map_manager->get_surf_map();
}
pcl::PointCloud::Ptr get_nonfeature_map(){
return map_manager->get_nonfeature_map();
}
pcl::PointCloud::Ptr get_init_ground_cloud(){
return initGroundCloud;
}
void MapIncrementLocal(const pcl::PointCloud::Ptr& laserCloudCornerStack,
const pcl::PointCloud::Ptr& laserCloudSurfStack,
const pcl::PointCloud::Ptr& laserCloudNonFeatureStack,
const Eigen::Matrix4d& transformTobeMapped);
private:
/** \brief store map points */
MAP_MANAGER* map_manager;
int init_ground_count;
Eigen::VectorXf init_ground_plane_coeff;
double para_PR[SLIDEWINDOWSIZE][6];
double para_VBias[SLIDEWINDOWSIZE][9];
MarginalizationInfo *last_marginalization_info = nullptr;
std::vector last_marginalization_parameter_blocks;
std::vector::Ptr> laserCloudCornerLast;
std::vector::Ptr> laserCloudSurfLast;
std::vector::Ptr> laserCloudNonFeatureLast;
pcl::PointCloud::Ptr laserCloudCornerFromLocal;
pcl::PointCloud::Ptr laserCloudSurfFromLocal;
pcl::PointCloud::Ptr laserCloudNonFeatureFromLocal;
pcl::PointCloud::Ptr laserCloudCornerForMap;
pcl::PointCloud::Ptr laserCloudSurfForMap;
pcl::PointCloud::Ptr laserCloudNonFeatureForMap;
pcl::PointCloud::Ptr initGroundCloud;
Eigen::Matrix4d transformForMap;
std::vector::Ptr> laserCloudCornerStack;
std::vector::Ptr> laserCloudSurfStack;
std::vector::Ptr> laserCloudNonFeatureStack;
pcl::KdTreeFLANN::Ptr kdtreeCornerFromLocal;
pcl::KdTreeFLANN::Ptr kdtreeSurfFromLocal;
pcl::KdTreeFLANN::Ptr kdtreeNonFeatureFromLocal;
pcl::VoxelGrid downSizeFilterCorner;
pcl::VoxelGrid downSizeFilterSurf;
pcl::VoxelGrid downSizeFilterNonFeature;
std::mutex mtx_Map;
std::thread threadMap;
pcl::KdTreeFLANN CornerKdMap[10000];
pcl::KdTreeFLANN SurfKdMap[10000];
pcl::KdTreeFLANN NonFeatureKdMap[10000];
pcl::PointCloud GlobalSurfMap[10000];
pcl::PointCloud GlobalCornerMap[10000];
pcl::PointCloud GlobalNonFeatureMap[10000];
int laserCenWidth_last = 10;
int laserCenHeight_last = 5;
int laserCenDepth_last = 10;
static const int localMapWindowSize = 50;
int localMapID = 0;
pcl::PointCloud::Ptr localCornerMap[localMapWindowSize];
pcl::PointCloud::Ptr localSurfMap[localMapWindowSize];
pcl::PointCloud::Ptr localNonFeatureMap[localMapWindowSize];
int map_update_ID = 0;
int map_skip_frame = 2; //every map_skip_frame frame update map
double plan_weight_tan = 0.0;
double thres_dist = 1.0;
};
#endif //LIO_LIVOX_ESTIMATOR_H
================================================
FILE: LIO-Livox/include/IMUIntegrator/IMUIntegrator.h
================================================
#ifndef LIO_LIVOX_IMUINTEGRATOR_H
#define LIO_LIVOX_IMUINTEGRATOR_H
#include
#include
#include
#include
#include
#include
#include "sophus/so3.hpp"
class IMUIntegrator{
public:
IMUIntegrator();
/** \brief constructor of IMUIntegrator
* \param[in] vIMU: IMU messages need to be integrated
*/
IMUIntegrator(std::vector vIMU);
void Reset();
/** \brief get delta quaternion after IMU integration
*/
const Eigen::Quaterniond & GetDeltaQ() const;
/** \brief get delta displacement after IMU integration
*/
const Eigen::Vector3d & GetDeltaP() const;
/** \brief get delta velocity after IMU integration
*/
const Eigen::Vector3d & GetDeltaV() const;
/** \brief get time span after IMU integration
*/
const double & GetDeltaTime() const;
/** \brief get linearized bias gyr
*/
const Eigen::Vector3d & GetBiasGyr() const;
/** \brief get linearized bias acc
*/
const Eigen::Vector3d& GetBiasAcc() const;
/** \brief get covariance matrix after IMU integration
*/
const Eigen::Matrix& GetCovariance();
/** \brief get jacobian matrix after IMU integration
*/
const Eigen::Matrix & GetJacobian() const;
/** \brief get average acceleration of IMU messages for initialization
*/
Eigen::Vector3d GetAverageAcc();
/** \brief push IMU message to the IMU buffer vimuMsg
* \param[in] imu: the IMU message need to be pushed
*/
void PushIMUMsg(const sensor_msgs::ImuConstPtr& imu);
void PushIMUMsg(const std::vector& vimu);
const std::vector & GetIMUMsg() const;
/** \brief only integrate gyro information of each IMU message stored in vimuMsg
* \param[in] lastTime: the left time boundary of vimuMsg
*/
void GyroIntegration(double lastTime);
/** \brief pre-integration of IMU messages stored in vimuMsg
*/
void PreIntegration(double lastTime, const Eigen::Vector3d& bg, const Eigen::Vector3d& ba);
/** \brief normal integration of IMU messages stored in vimuMsg
*/
void Integration(){}
public:
const double acc_n = 0.08;
const double gyr_n = 0.004;
const double acc_w = 2.0e-4;
const double gyr_w = 2.0e-5;
constexpr static const double lidar_m = 6e-3;
constexpr static const double gnorm = 9.805;
enum JacobianOrder
{
O_P = 0,
O_R = 3,
O_V = 6,
O_BG = 9,
O_BA = 12
};
private:
std::vector vimuMsg;
Eigen::Quaterniond dq;
Eigen::Vector3d dp;
Eigen::Vector3d dv;
Eigen::Vector3d linearized_bg;
Eigen::Vector3d linearized_ba;
Eigen::Matrix covariance;
Eigen::Matrix jacobian;
Eigen::Matrix noise;
double dtime;
};
#endif //LIO_LIVOX_IMUINTEGRATOR_H
================================================
FILE: LIO-Livox/include/LidarFeatureExtractor/LidarFeatureExtractor.h
================================================
#ifndef LIO_LIVOX_LIDARFEATUREEXTRACTOR_H
#define LIO_LIVOX_LIDARFEATUREEXTRACTOR_H
#include
#include
#include
#include
#include
#include
#include
#include
#include "opencv2/core.hpp"
#include "segment/segment.hpp"
class LidarFeatureExtractor{
typedef pcl::PointXYZINormal PointType;
public:
/** \brief constructor of LidarFeatureExtractor
* \param[in] n_scans: lines used to extract lidar features
*/
LidarFeatureExtractor(int n_scans,int NumCurvSize,float DistanceFaraway,int NumFlat,int PartNum,float FlatThreshold,
float BreakCornerDis,float LidarNearestDis,float KdTreeCornerOutlierDis);
/** \brief transform float to int
*/
static uint32_t _float_as_int(float f){
union{uint32_t i; float f;} conv{};
conv.f = f;
return conv.i;
}
/** \brief transform int to float
*/
static float _int_as_float(uint32_t i){
union{float f; uint32_t i;} conv{};
conv.i = i;
return conv.f;
}
/** \brief Determine whether the point_list is flat
* \param[in] point_list: points need to be judged
* \param[in] plane_threshold
*/
bool plane_judge(const std::vector& point_list,const int plane_threshold);
/** \brief Detect lidar feature points
* \param[in] cloud: original lidar cloud need to be detected
* \param[in] pointsLessSharp: less sharp index of cloud
* \param[in] pointsLessFlat: less flat index of cloud
*/
void detectFeaturePoint(pcl::PointCloud::Ptr& cloud,
std::vector& pointsLessSharp,
std::vector& pointsLessFlat);
void detectFeaturePoint2(pcl::PointCloud::Ptr& cloud,
pcl::PointCloud::Ptr& pointsLessFlat,
pcl::PointCloud::Ptr& pointsNonFeature);
void detectFeaturePoint3(pcl::PointCloud::Ptr& cloud,
std::vector& pointsLessSharp);
void FeatureExtract_with_segment(const livox_ros_driver::CustomMsgConstPtr &msg,
pcl::PointCloud::Ptr& laserCloud,
pcl::PointCloud::Ptr& laserConerFeature,
pcl::PointCloud::Ptr& laserSurfFeature,
pcl::PointCloud::Ptr& laserNonFeature,
sensor_msgs::PointCloud2 &msg2,
int Used_Line = 1);
/** \brief Detect lidar feature points of CustomMsg
* \param[in] msg: original CustomMsg need to be detected
* \param[in] laserCloud: transform CustomMsg to pcl point cloud format
* \param[in] laserConerFeature: less Coner features extracted from laserCloud
* \param[in] laserSurfFeature: less Surf features extracted from laserCloud
*/
void FeatureExtract(const livox_ros_driver::CustomMsgConstPtr &msg,
pcl::PointCloud::Ptr& laserCloud,
pcl::PointCloud::Ptr& laserConerFeature,
pcl::PointCloud::Ptr& laserSurfFeature,
int Used_Line = 1);
private:
/** \brief lines used to extract lidar features */
const int N_SCANS;
/** \brief store original points of each line */
std::vector::Ptr> vlines;
/** \brief store corner feature index of each line */
std::vector> vcorner;
/** \brief store surf feature index of each line */
std::vector> vsurf;
int thNumCurvSize;
float thDistanceFaraway;
int thNumFlat;
int thPartNum;
float thFlatThreshold;
float thBreakCornerDis;
float thLidarNearestDis;
};
#endif //LIO_LIVOX_LIDARFEATUREEXTRACTOR_H
================================================
FILE: LIO-Livox/include/MapManager/Map_Manager.h
================================================
#ifndef LIO_LIVOX_MAP_MANAGER_H
#define LIO_LIVOX_MAP_MANAGER_H
#include
#include
#include
#include
#include
class MAP_MANAGER{
typedef pcl::PointXYZINormal PointType;
public:
std::mutex mtx_MapManager;
/** \brief constructor of MAP_MANAGER */
MAP_MANAGER(const float& filter_corner, const float& filter_surf);
static size_t ToIndex(int i, int j, int k);
/** \brief transform float to int
*/
static uint32_t _float_as_int(float f){
union{uint32_t i; float f;} conv{};
conv.f = f;
return conv.i;
}
/** \brief transform int to float
*/
static float _int_as_float(uint32_t i){
union{float f; uint32_t i;} conv{};
conv.i = i;
return conv.f;
}
/** \brief transform point pi to the MAP coordinate
* \param[in] pi: point to be transformed
* \param[in] po: point after transfomation
* \param[in] _transformTobeMapped: transform matrix between pi and po
*/
static void pointAssociateToMap(PointType const * const pi,
PointType * const po,
const Eigen::Matrix4d& _transformTobeMapped);
void featureAssociateToMap(const pcl::PointCloud::Ptr& laserCloudCorner,
const pcl::PointCloud::Ptr& laserCloudSurf,
const pcl::PointCloud::Ptr& laserCloudNonFeature,
const pcl::PointCloud::Ptr& laserCloudCornerToMap,
const pcl::PointCloud::Ptr& laserCloudSurfToMap,
const pcl::PointCloud::Ptr& laserCloudNonFeatureToMap,
const Eigen::Matrix4d& transformTobeMapped);
/** \brief add new lidar points to the map
* \param[in] laserCloudCornerStack: coner feature points that need to be added to map
* \param[in] laserCloudSurfStack: surf feature points that need to be added to map
* \param[in] transformTobeMapped: transform matrix of the lidar pose
*/
void MapIncrement(const pcl::PointCloud::Ptr& laserCloudCornerStack,
const pcl::PointCloud::Ptr& laserCloudSurfStack,
const pcl::PointCloud::Ptr& laserCloudNonFeatureStack,
const Eigen::Matrix4d& transformTobeMapped);
/** \brief retrieve map points according to the lidar pose
* \param[in] laserCloudCornerFromMap: store coner feature points retrieved from map
* \param[in] laserCloudSurfFromMap: tore surf feature points retrieved from map
* \param[in] transformTobeMapped: transform matrix of the lidar pose
*/
void MapMove(const Eigen::Matrix4d& transformTobeMapped);
size_t FindUsedCornerMap(const PointType *p,int a,int b,int c);
size_t FindUsedSurfMap(const PointType *p,int a,int b,int c);
size_t FindUsedNonFeatureMap(const PointType *p,int a,int b,int c);
pcl::KdTreeFLANN getCornerKdMap(int i){
return CornerKdMap_last[i];
}
pcl::KdTreeFLANN getSurfKdMap(int i){
return SurfKdMap_last[i];
}
pcl::KdTreeFLANN getNonFeatureKdMap(int i){
return NonFeatureKdMap_last[i];
}
pcl::PointCloud::Ptr get_corner_map(){
return laserCloudCornerFromMap;
}
pcl::PointCloud::Ptr get_surf_map(){
return laserCloudSurfFromMap;
}
pcl::PointCloud::Ptr get_nonfeature_map(){
return laserCloudNonFeatureFromMap;
}
int get_map_current_pos(){
return currentUpdatePos;
}
int get_laserCloudCenWidth_last(){
return laserCloudCenWidth_last;
}
int get_laserCloudCenHeight_last(){
return laserCloudCenHeight_last;
}
int get_laserCloudCenDepth_last(){
return laserCloudCenDepth_last;
}
pcl::PointCloud laserCloudSurf_for_match[4851];
pcl::PointCloud laserCloudCorner_for_match[4851];
pcl::PointCloud laserCloudNonFeature_for_match[4851];
private:
int laserCloudCenWidth = 10;
int laserCloudCenHeight = 5;
int laserCloudCenDepth = 10;
int laserCloudCenWidth_last = 10;
int laserCloudCenHeight_last = 5;
int laserCloudCenDepth_last = 10;
static const int laserCloudWidth = 21;
static const int laserCloudHeight = 11;
static const int laserCloudDepth = 21;
static const int laserCloudNum = laserCloudWidth * laserCloudHeight * laserCloudDepth;//4851
pcl::PointCloud::Ptr laserCloudCornerArray[laserCloudNum];
pcl::PointCloud::Ptr laserCloudSurfArray[laserCloudNum];
pcl::PointCloud::Ptr laserCloudNonFeatureArray[laserCloudNum];
pcl::PointCloud::Ptr laserCloudCornerArrayStack[laserCloudNum];
pcl::PointCloud::Ptr laserCloudSurfArrayStack[laserCloudNum];
pcl::PointCloud::Ptr laserCloudNonFeatureArrayStack[laserCloudNum];
pcl::VoxelGrid downSizeFilterCorner;
pcl::VoxelGrid downSizeFilterSurf;
pcl::VoxelGrid downSizeFilterNonFeature;
pcl::PointCloud::Ptr laserCloudCornerFromMap;
pcl::PointCloud::Ptr laserCloudSurfFromMap;
pcl::PointCloud::Ptr laserCloudNonFeatureFromMap;
pcl::KdTreeFLANN::Ptr laserCloudCornerKdMap[laserCloudNum];
pcl::KdTreeFLANN::Ptr laserCloudSurfKdMap[laserCloudNum];
pcl::KdTreeFLANN::Ptr laserCloudNonFeatureKdMap[laserCloudNum];
pcl::KdTreeFLANN CornerKdMap_copy[laserCloudNum];
pcl::KdTreeFLANN SurfKdMap_copy[laserCloudNum];
pcl::KdTreeFLANN NonFeatureKdMap_copy[laserCloudNum];
pcl::KdTreeFLANN CornerKdMap_last[laserCloudNum];
pcl::KdTreeFLANN SurfKdMap_last[laserCloudNum];
pcl::KdTreeFLANN NonFeatureKdMap_last[laserCloudNum];
static const int localMapWindowSize = 60;
pcl::PointCloud::Ptr localCornerMap[localMapWindowSize];
pcl::PointCloud::Ptr localSurfMap[localMapWindowSize];
pcl::PointCloud::Ptr localNonFeatureMap[localMapWindowSize];
int localMapID = 0;
int currentUpdatePos = 0;
int estimatorPos = 0;
};
#endif //LIO_LIVOX_MAP_MANAGER_H
================================================
FILE: LIO-Livox/include/segment/pointsCorrect.hpp
================================================
#ifndef _COMMON_HPP
#define _CONNON_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef struct
{
Eigen::Matrix3f eigenVectorsPCA;
Eigen::Vector3f eigenValuesPCA;
std::vector neibors;
} SNeiborPCA_cor;
int GetNeiborPCA_cor(SNeiborPCA_cor &npca, pcl::PointCloud::Ptr cloud, pcl::KdTreeFLANN kdtree, pcl::PointXYZ searchPoint, float fSearchRadius);
int FilterGndForPos_cor(float* outPoints,float*inPoints,int inNum);
int CalGndPos_cor(float *gnd, float *fPoints,int pointNum,float fSearchRadius);
int GetRTMatrix_cor(float *RTM, float *v0, float *v1);
int CorrectPoints_cor(float *fPoints,int pointNum,float *gndPos);
int GetGndPos(float *pos, float *fPoints,int pointNum);
#endif
================================================
FILE: LIO-Livox/include/segment/segment.hpp
================================================
#ifndef _SEGMENT_HPP
#define _SEGMENT_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "pointsCorrect.hpp"
using namespace std;
#define SELF_CALI_FRAMES 20
#define GND_IMG_NX 150
#define GND_IMG_NY 400
#define GND_IMG_DX 0.2
#define GND_IMG_DY 0.2
#define GND_IMG_OFFX 40
#define GND_IMG_OFFY 40
#define GND_IMG_NX1 24
#define GND_IMG_NY1 20
#define GND_IMG_DX1 4
#define GND_IMG_DY1 4
#define GND_IMG_OFFX1 40
#define GND_IMG_OFFY1 40
#define DN_SAMPLE_IMG_NX 600 //(GND_IMG_NX)
#define DN_SAMPLE_IMG_NY 200 //(GND_IMG_NY)
#define DN_SAMPLE_IMG_NZ 100
#define DN_SAMPLE_IMG_DX 0.4 //(GND_IMG_DX)
#define DN_SAMPLE_IMG_DY 0.4 //(GND_IMG_DY)
#define DN_SAMPLE_IMG_DZ 0.2
#define DN_SAMPLE_IMG_OFFX 40 //(GND_IMG_OFFX)
#define DN_SAMPLE_IMG_OFFY 40 //(GND_IMG_OFFY)
#define DN_SAMPLE_IMG_OFFZ 2.5//2.5
#define FREE_ANG_NUM 360
#define FREE_PI (3.14159265)
#define FREE_DELTA_ANG (FREE_PI*2/FREE_ANG_NUM)
typedef struct
{
Eigen::Matrix3f eigenVectorsPCA;
Eigen::Vector3f eigenValuesPCA;
std::vector neibors;
} SNeiborPCA;
typedef struct
{
// basic
int pnum;
float xmin;
float xmax;
float ymin;
float ymax;
float zmin;
float zmax;
float zmean;
// pca
float d0[3];
float d1[3];
float center[3];
float obb[8];
int cls;//类别
} SClusterFeature;
int FilterGndForPos(float* outPoints,float*inPoints,int inNum);
int CalNomarls(float *nvects, float *fPoints,int pointNum,float fSearchRadius);
int CalGndPos(float *gnd, float *fPoints,int pointNum,float fSearchRadius);
int GetNeiborPCA(SNeiborPCA &npca, pcl::PointCloud::Ptr cloud,
pcl::KdTreeFLANN kdtree, pcl::PointXYZ searchPoint, float fSearchRadius);
int CorrectPoints(float *fPoints,int pointNum,float *gndPos);
// 地面上物体分割
int AbvGndSeg(int *pLabel, float *fPoints, int pointNum);
int SegBG(int *pLabel, pcl::PointCloud::Ptr cloud, pcl::KdTreeFLANN &kdtree, float fSearchRadius);
SClusterFeature FindACluster(int *pLabel, int seedId, int labelId, pcl::PointCloud::Ptr cloud, pcl::KdTreeFLANN &kdtree, float fSearchRadius, float thrHeight);
int SegObjects(int *pLabel, pcl::PointCloud::Ptr cloud, pcl::KdTreeFLANN &kdtree, float fSearchRadius);
int CalFreeRegion(float *pFreeDis, float *fPoints,int *pLabel,int pointNum);
int FreeSeg(float *fPoints,int *pLabel,int pointNum);
int CompleteObjects(int *pLabel, pcl::PointCloud::Ptr cloud, pcl::KdTreeFLANN &kdtree, float fSearchRadius);
int ExpandObjects(int *pLabel, float* fPoints, int pointNum, float fSearchRadius);
int ExpandBG(int *pLabel, float* fPoints, int pointNum, float fSearchRadius);
// 地面分割
int GndSeg(int* pLabel,float *fPoints,int pointNum,float fSearchRadius);
class PCSeg
{
public:
PCSeg();
// functions
int DoSeg(int *pLabel, float* fPoints1, int pointNum);
int GetMainVectors(float*fPoints, int* pLabel, int pointNum);
int EncodeFeatures(float *pFeas);
int DoBoundaryDetection(float* fPoints1,int *pLabel1,int pointNum);
int DoTrafficLineDet(float *fPoints1,int *pLabel1,int pointNum);
int CorrectPoints(float *fPoints,int pointNum,float *gndPos);
float *PrePoints;
int numPrePoints = 0;
float gnd_pos[100*6];
int gnd_vet_len = 0;
int laneType=0;
float lanePosition[2] = {0};
// vars
unsigned char *pVImg;
float gndPos[6];
int posFlag;
// cluster features
float pVectors[256*3];
float pCenters[256*3];//重心
int pnum[256];
int objClass[256];
float zs[256];
float pOBBs[256*8];
float CBBox[256*7];//(a,x,y,z,l,w,h)
int clusterNum;
float *corPoints;
int corNum;
~PCSeg();
};
SClusterFeature CalBBox(float *fPoints,int pointNum);
SClusterFeature CalOBB(float *fPoints,int pointNum);
#endif
================================================
FILE: LIO-Livox/include/sophus/average.hpp
================================================
/// @file
/// Calculation of biinvariant means.
#ifndef SOPHUS_AVERAGE_HPP
#define SOPHUS_AVERAGE_HPP
#include "common.hpp"
#include "rxso2.hpp"
#include "rxso3.hpp"
#include "se2.hpp"
#include "se3.hpp"
#include "sim2.hpp"
#include "sim3.hpp"
#include "so2.hpp"
#include "so3.hpp"
namespace Sophus {
/// Calculates mean iteratively.
///
/// Returns ``nullopt`` if it does not converge.
///
template
optional iterativeMean(
SequenceContainer const& foo_Ts_bar, int max_num_iterations) {
size_t N = foo_Ts_bar.size();
SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
using Group = typename SequenceContainer::value_type;
using Scalar = typename Group::Scalar;
using Tangent = typename Group::Tangent;
// This implements the algorithm in the beginning of Sec. 4.2 in
// ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
Group foo_T_average = foo_Ts_bar.front();
Scalar w = Scalar(1. / N);
for (int i = 0; i < max_num_iterations; ++i) {
Tangent average;
setToZero(average);
for (Group const& foo_T_bar : foo_Ts_bar) {
average += w * (foo_T_average.inverse() * foo_T_bar).log();
}
Group foo_T_newaverage = foo_T_average * Group::exp(average);
if (squaredNorm(
(foo_T_newaverage.inverse() * foo_T_average).log()) <
Constants::epsilon()) {
return foo_T_newaverage;
}
foo_T_average = foo_T_newaverage;
}
// LCOV_EXCL_START
return nullopt;
// LCOV_EXCL_STOP
}
#ifdef DOXYGEN_SHOULD_SKIP_THIS
/// Mean implementation for any Lie group.
template
optional average(
SequenceContainer const& foo_Ts_bar);
#else
// Mean implementation for SO(2).
template
enable_if_t<
std::is_same >::value,
optional >
average(SequenceContainer const& foo_Ts_bar) {
// This implements rotational part of Proposition 12 from Sec. 6.2 of
// ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
SO2 foo_T_average = foo_Ts_bar.front();
Scalar w = Scalar(1. / N);
Scalar average(0);
for (SO2 const& foo_T_bar : foo_Ts_bar) {
average += w * (foo_T_average.inverse() * foo_T_bar).log();
}
return foo_T_average * SO2::exp(average);
}
// Mean implementation for RxSO(2).
template
enable_if_t<
std::is_same >::value,
optional >
average(SequenceContainer const& foo_Ts_bar) {
size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
RxSO2 foo_T_average = foo_Ts_bar.front();
Scalar w = Scalar(1. / N);
Vector2 average(Scalar(0), Scalar(0));
for (RxSO2 const& foo_T_bar : foo_Ts_bar) {
average += w * (foo_T_average.inverse() * foo_T_bar).log();
}
return foo_T_average * RxSO2::exp(average);
}
namespace details {
template
void getQuaternion(T const&);
template
Eigen::Quaternion getUnitQuaternion(SO3 const& R) {
return R.unit_quaternion();
}
template
Eigen::Quaternion getUnitQuaternion(RxSO3 const& sR) {
return sR.so3().unit_quaternion();
}
template
Eigen::Quaternion averageUnitQuaternion(
SequenceContainer const& foo_Ts_bar) {
// This: http://stackoverflow.com/a/27410865/1221742
size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
Eigen::Matrix Q(4, N);
int i = 0;
Scalar w = Scalar(1. / N);
for (auto const& foo_T_bar : foo_Ts_bar) {
Q.col(i) = w * details::getUnitQuaternion(foo_T_bar).coeffs();
++i;
}
Eigen::Matrix QQt = Q * Q.transpose();
// TODO: Figure out why we can't use SelfAdjointEigenSolver here.
Eigen::EigenSolver > es(QQt);
std::complex max_eigenvalue = es.eigenvalues()[0];
Eigen::Matrix, 4, 1> max_eigenvector =
es.eigenvectors().col(0);
for (int i = 1; i < 4; i++) {
if (std::norm(es.eigenvalues()[i]) > std::norm(max_eigenvalue)) {
max_eigenvalue = es.eigenvalues()[i];
max_eigenvector = es.eigenvectors().col(i);
}
}
Eigen::Quaternion quat;
quat.coeffs() << //
max_eigenvector[0].real(), //
max_eigenvector[1].real(), //
max_eigenvector[2].real(), //
max_eigenvector[3].real();
return quat;
}
} // namespace details
// Mean implementation for SO(3).
//
// TODO: Detect degenerated cases and return nullopt.
template
enable_if_t<
std::is_same >::value,
optional >
average(SequenceContainer const& foo_Ts_bar) {
return SO3(details::averageUnitQuaternion(foo_Ts_bar));
}
// Mean implementation for R x SO(3).
template
enable_if_t<
std::is_same >::value,
optional >
average(SequenceContainer const& foo_Ts_bar) {
size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
Scalar scale_sum = Scalar(0);
using std::exp;
using std::log;
for (RxSO3