diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index f32ffb5..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2019 Jariullah Safi - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -cmake_minimum_required(VERSION 3.0.0) -project(yag_slam) - -find_package(catkin QUIET) - -if (catkin_FOUND) - include_directories(include) - catkin_package( - INCLUDE_DIRS include - ) -else() - include_directories(include) -endif() - -add_subdirectory(pybind11) - -pybind11_add_module(yag_slam_cpp src/PythonInterface.cpp src/Impls.cpp src/ScanMatcher.cpp) -target_link_libraries(yag_slam_cpp) - -if (catkin_FOUND) - install(TARGETS yag_slam_cpp - LIBRARY DESTINATION ${CATKIN_GLOBAL_PYTHON_DESTINATION} - ) - install(DIRECTORY yag_slam DESTINATION ${CATKIN_GLOBAL_PYTHON_DESTINATION}) -endif() \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 507ff87..0000000 --- a/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -setup: - git submodule update --init - pip install pybind11_cmake \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100755 index 87bb8ca..0000000 --- a/build.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -#docker run --rm -v `pwd`:/repo --rm safijari/manylinux_2_28-x64 /repo/run_build.sh - -cd /repo - -rm -r build -rm -r dist - -set -e - -yum install boost-thread boost-atomic boost-chrono boost-devel -y - -/opt/python/cp38-cp38/bin/pip install -U auditwheel - -for folder in /opt/python/cp3* -do - echo $folder - $folder/bin/pip install pybind11 pybind11-cmake - $folder/bin/python setup.py bdist_wheel -done - -cd dist - -for file in ./* -do - /opt/python/cp38-cp38/bin/auditwheel -v repair --plat $1 $file -done diff --git a/include/AdditionalMath.h b/include/AdditionalMath.h deleted file mode 100644 index 16fb0ba..0000000 --- a/include/AdditionalMath.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2010 SRI International - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef MP_MATH_H -#define MP_MATH_H - -#include -#include -#include -#include - -/** - * Platform independent pi definitions - */ -const double KT_PI = 3.14159265358979323846; // The value of PI -const double KT_2PI = 6.28318530717958647692; // 2 * PI -const double KT_PI_2 = 1.57079632679489661923; // PI / 2 -const double KT_PI_180 = 0.01745329251994329577; // PI / 180 -const double KT_180_PI = 57.29577951308232087685; // 180 / PI - -/** - * Lets define a small number! - */ -const double KT_TOLERANCE = 1e-06; - -/** - * Lets define max value of int32_t (int32_t) to use it to mark invalid scans - */ - -const int32_t INVALID_SCAN = std::numeric_limits::max(); - -namespace amath { -/** - * Converts degrees into radians - * @param degrees - * @return radian equivalent of degrees - */ -inline double DegreesToRadians(double degrees) { return degrees * KT_PI_180; } - -/** - * Converts radians into degrees - * @param radians - * @return degree equivalent of radians - */ -inline double RadiansToDegrees(double radians) { return radians * KT_180_PI; } - -/** - * Square function - * @param value - * @return square of value - */ -template inline T Square(T value) { return (value * value); } - -/** - * Round function - * @param value - * @return rounds value to the nearest whole number (as double) - */ -inline double Round(double value) { - return value >= 0.0 ? floor(value + 0.5) : ceil(value - 0.5); -} - -/** - * Binary minimum function - * @param value1 - * @param value2 - * @return the lesser of value1 and value2 - */ -template -inline const T &Minimum(const T &value1, const T &value2) { - return value1 < value2 ? value1 : value2; -} - -/** - * Binary maximum function - * @param value1 - * @param value2 - * @return the greater of value1 and value2 - */ -template -inline const T &Maximum(const T &value1, const T &value2) { - return value1 > value2 ? value1 : value2; -} - -/** - * Clips a number to the specified minimum and maximum values. - * @param n number to be clipped - * @param minValue minimum value - * @param maxValue maximum value - * @return the clipped value - */ -template -inline const T &Clip(const T &n, const T &minValue, const T &maxValue) { - return Minimum(Maximum(n, minValue), maxValue); -} - -/** - * Checks whether two numbers are equal within a certain tolerance. - * @param a - * @param b - * @return true if a and b differ by at most a certain tolerance. - */ -inline bool DoubleEqual(double a, double b) { - double delta = a - b; - return delta < 0.0 ? delta >= -KT_TOLERANCE : delta <= KT_TOLERANCE; -} - -/** - * Checks whether value is in the range [0;maximum) - * @param value - * @param maximum - */ -template inline bool IsUpTo(const T &value, const T &maximum) { - return (value >= 0 && value < maximum); -} - -/** - * Checks whether value is in the range [0;maximum) - * Specialized version for unsigned int (uint32_t) - * @param value - * @param maximum - */ -template <> -inline bool IsUpTo(const uint32_t &value, const uint32_t &maximum) { - return (value < maximum); -} - -/** - * Checks whether value is in the range [a;b] - * @param value - * @param a - * @param b - */ -template -inline bool InRange(const T &value, const T &a, const T &b) { - return (value >= a && value <= b); -} - - -template -inline bool InRange(T &value, T &a, T &b) { - return (value >= a && value <= b); -} - -/** - * Normalizes angle to be in the range of [-pi, pi] - * @param angle to be normalized - * @return normalized angle - */ -inline double NormalizeAngle(double angle) { - while (angle < -KT_PI) { - if (angle < -KT_2PI) { - angle += (uint32_t)(angle / -KT_2PI) * KT_2PI; - } else { - angle += KT_2PI; - } - } - - while (angle > KT_PI) { - if (angle > KT_2PI) { - angle -= (uint32_t)(angle / KT_2PI) * KT_2PI; - } else { - angle -= KT_2PI; - } - } - - assert(amath::InRange(angle, -KT_PI, KT_PI)); - - return angle; -} - -/** - * Returns an equivalent angle to the first parameter such that the difference - * when the second parameter is subtracted from this new value is an angle - * in the normalized range of [-pi, pi], i.e. abs(minuend - subtrahend) <= pi. - * @param minuend - * @param subtrahend - * @return normalized angle - */ -inline double NormalizeAngleDifference(double minuend, double subtrahend) { - while (minuend - subtrahend < -KT_PI) { - minuend += KT_2PI; - } - - while (minuend - subtrahend > KT_PI) { - minuend -= KT_2PI; - } - - return minuend; -} - -/** - * Align a value to the alignValue. - * The alignValue should be the power of two (2, 4, 8, 16, 32 and so on) - * @param value - * @param alignValue - * @return aligned value - */ -template inline T AlignValue(size_t value, size_t alignValue = 8) { - return static_cast((value + (alignValue - 1)) & ~(alignValue - 1)); -} -} // namespace math - -#endif // MP_MATH_H diff --git a/include/BoundingBox2.h b/include/BoundingBox2.h deleted file mode 100644 index 66db08a..0000000 --- a/include/BoundingBox2.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef BBOX2_H -#define BBOX2_H - -#include -#include "Vector2.h" -#include "Size2.h" - -class BoundingBox2 { -public: - /* - * Default constructor - */ - BoundingBox2() - : m_Minimum(999999999999999999.99999, 999999999999999999.99999), - m_Maximum(-999999999999999999.99999, -999999999999999999.99999) {} - -public: - /** - * Get bounding box minimum - */ - inline const Vector2 &GetMinimum() const { return m_Minimum; } - - /** - * Set bounding box minimum - */ - inline void SetMinimum(const Vector2 &mMinimum) { - m_Minimum = mMinimum; - } - - /** - * Get bounding box maximum - */ - inline const Vector2 &GetMaximum() const { return m_Maximum; } - - /** - * Set bounding box maximum - */ - inline void SetMaximum(const Vector2 &rMaximum) { - m_Maximum = rMaximum; - } - - /** - * Get the size of the bounding box - */ - inline Size2 GetSize() const { - Vector2 size = m_Maximum - m_Minimum; - - return Size2(size.GetX(), size.GetY()); - } - - /** - * Add vector to bounding box - */ - inline void Add(const Vector2 &rPoint) { - m_Minimum.MakeFloor(rPoint); - m_Maximum.MakeCeil(rPoint); - } - - /** - * Add other bounding box to bounding box - */ - inline void Add(const BoundingBox2 &rBoundingBox) { - Add(rBoundingBox.GetMinimum()); - Add(rBoundingBox.GetMaximum()); - } - - /** - * Whether the given point is in the bounds of this box - * @param rPoint - * @return in bounds? - */ - inline bool IsInBounds(const Vector2 &rPoint) const { - return (amath::InRange(rPoint.GetX(), m_Minimum.GetX(), m_Maximum.GetX()) && - amath::InRange(rPoint.GetY(), m_Minimum.GetY(), m_Maximum.GetY())); - } - -private: - Vector2 m_Minimum; - Vector2 m_Maximum; -}; // BoundingBox2 - -#endif diff --git a/include/CoordinateConverter.h b/include/CoordinateConverter.h deleted file mode 100644 index cfa6f01..0000000 --- a/include/CoordinateConverter.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef COORD_CVTR_H -#define COORD_CVTR_H - -#include "BoundingBox2.h" -#include "AdditionalMath.h" - -/** - * The CoordinateConverter class is used to convert coordinates between world - * and grid coordinates In world coordinates 1.0 = 1 meter where 1 in grid - * coordinates = 1 pixel! Default scale for coordinate converter is 20 that - * converters to 1 pixel = 0.05 meter - */ -class CoordinateConverter { -public: - /** - * Default constructor - */ - CoordinateConverter() : m_Scale(20.0) {} - -public: - /** - * Scales the value - * @param value - * @return scaled value - */ - inline double Transform(double value) { return value * m_Scale; } - - /** - * Converts the point from world coordinates to grid coordinates - * @param rWorld world coordinate - * @param flipY - * @return grid coordinate - */ - inline Vector2 WorldToGrid(const Vector2 &rWorld, - bool flipY = false) const { - double gridX = (rWorld.GetX() - m_Offset.GetX()) * m_Scale; - double gridY = 0.0; - - if (flipY == false) { - gridY = (rWorld.GetY() - m_Offset.GetY()) * m_Scale; - } else { - gridY = (m_Size.GetHeight() / m_Scale - rWorld.GetY() + m_Offset.GetY()) * - m_Scale; - } - - return Vector2(static_cast(amath::Round(gridX)), - static_cast(amath::Round(gridY))); - } - - /** - * Converts the point from grid coordinates to world coordinates - * @param rGrid world coordinate - * @param flipY - * @return world coordinate - */ - inline Vector2 GridToWorld(const Vector2 &rGrid, - bool flipY = false) const { - double worldX = m_Offset.GetX() + rGrid.GetX() / m_Scale; - double worldY = 0.0; - - if (flipY == false) { - worldY = m_Offset.GetY() + rGrid.GetY() / m_Scale; - } else { - worldY = m_Offset.GetY() + (m_Size.GetHeight() - rGrid.GetY()) / m_Scale; - } - - return Vector2(worldX, worldY); - } - - /** - * Gets the scale - * @return scale - */ - inline double GetScale() const { return m_Scale; } - - /** - * Sets the scale - * @param scale - */ - inline void SetScale(double scale) { m_Scale = scale; } - - /** - * Gets the offset - * @return offset - */ - inline const Vector2 &GetOffset() const { return m_Offset; } - - /** - * Sets the offset - * @param rOffset - */ - inline void SetOffset(const Vector2 &rOffset) { m_Offset = rOffset; } - - /** - * Sets the size - * @param rSize - */ - inline void SetSize(const Size2 &rSize) { m_Size = rSize; } - - /** - * Gets the size - * @return size - */ - inline const Size2 &GetSize() const { return m_Size; } - - /** - * Gets the resolution - * @return resolution - */ - inline double GetResolution() const { return 1.0 / m_Scale; } - - /** - * Sets the resolution - * @param resolution - */ - inline void SetResolution(double resolution) { m_Scale = 1.0 / resolution; } - - /** - * Gets the bounding box - * @return bounding box - */ - inline BoundingBox2 GetBoundingBox() const { - BoundingBox2 box; - - double minX = GetOffset().GetX(); - double minY = GetOffset().GetY(); - double maxX = minX + GetSize().GetWidth() * GetResolution(); - double maxY = minY + GetSize().GetHeight() * GetResolution(); - - box.SetMinimum(GetOffset()); - box.SetMaximum(Vector2(maxX, maxY)); - return box; - } - -private: - Size2 m_Size; - double m_Scale; - - Vector2 m_Offset; -}; // CoordinateConverter - -#endif diff --git a/include/CorrelationGrid.h b/include/CorrelationGrid.h deleted file mode 100644 index ea7672e..0000000 --- a/include/CorrelationGrid.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef CORRELATION_GRID_H -#define CORRELATION_GRID_H - -#include "Grid.h" -#include "Rectangle2.h" - -class CorrelationGrid : public Grid { -public: - /** - * Destructor - */ - virtual ~CorrelationGrid() { delete[] m_pKernel; } - -public: - /** - * Create a correlation grid of given size and parameters - * @param width - * @param height - * @param resolution - * @param smearDeviation - * @return correlation grid - */ - static CorrelationGrid *CreateGrid(int32_t width, int32_t height, - double resolution, double smearDeviation) { - assert(resolution != 0.0); - - // +1 in case of roundoff - uint32_t borderSize = GetHalfKernelSize(smearDeviation, resolution) + 1; - - CorrelationGrid *pGrid = new CorrelationGrid(width, height, borderSize, - resolution, smearDeviation); - - return pGrid; - } - - /** - * Gets the index into the data pointer of the given grid coordinate - * @param rGrid - * @param boundaryCheck - * @return grid index - */ - virtual int32_t GridIndex(const Vector2 &rGrid, - bool boundaryCheck = true) const { - int32_t x = rGrid.GetX() + m_Roi.GetX(); - int32_t y = rGrid.GetY() + m_Roi.GetY(); - - return Grid::GridIndex(Vector2(x, y), boundaryCheck); - } - - /** - * Get the Region Of Interest (ROI) - * @return region of interest - */ - inline const Rectangle2 &GetROI() const { return m_Roi; } - - /** - * Sets the Region Of Interest (ROI) - * @param roi - */ - inline void SetROI(const Rectangle2 &roi) { m_Roi = roi; } - - /** - * Smear cell if the cell at the given point is marked as "occupied" - * @param rGridPoint - */ - inline void SmearPoint(const Vector2 &rGridPoint) { - assert(m_pKernel != NULL); - - int gridIndex = GridIndex(rGridPoint); - if (GetDataPointer()[gridIndex] != GridStates_Occupied) { - return; - } - - int32_t halfKernel = m_KernelSize / 2; - - // apply kernel - for (int32_t j = -halfKernel; j <= halfKernel; j++) { - uint8_t *pGridAdr = GetDataPointer( - Vector2(rGridPoint.GetX(), rGridPoint.GetY() + j)); - - int32_t kernelConstant = (halfKernel) + m_KernelSize * (j + halfKernel); - - // if a point is on the edge of the grid, there is no problem - // with running over the edge of allowable memory, because - // the grid has margins to compensate for the kernel size - for (int32_t i = -halfKernel; i <= halfKernel; i++) { - int32_t kernelArrayIndex = i + kernelConstant; - - uint8_t kernelValue = m_pKernel[kernelArrayIndex]; - if (kernelValue > pGridAdr[i]) { - // kernel value is greater, so set it to kernel value - pGridAdr[i] = kernelValue; - } - } - } - } - -protected: - /** - * Constructs a correlation grid of given size and parameters - * @param width - * @param height - * @param borderSize - * @param resolution - * @param smearDeviation - */ - CorrelationGrid(uint32_t width, uint32_t height, uint32_t borderSize, - double resolution, double smearDeviation) - : Grid(width + borderSize * 2, height + borderSize * 2), - m_SmearDeviation(smearDeviation), m_pKernel(NULL) { - GetCoordinateConverter()->SetScale(1.0 / resolution); - - // setup region of interest - m_Roi = Rectangle2(borderSize, borderSize, width, height); - - // calculate kernel - CalculateKernel(); - } - - /** - * Sets up the kernel for grid smearing. - */ - virtual void CalculateKernel() { - double resolution = GetResolution(); - - assert(resolution != 0.0); - assert(m_SmearDeviation != 0.0); - - // min and max distance deviation for smearing; - // will smear for two standard deviations, so deviation must be at least 1/2 - // of the resolution - const double MIN_SMEAR_DISTANCE_DEVIATION = 0.5 * resolution; - const double MAX_SMEAR_DISTANCE_DEVIATION = 10 * resolution; - - // check if given value too small or too big - if (!amath::InRange(m_SmearDeviation, MIN_SMEAR_DISTANCE_DEVIATION, - MAX_SMEAR_DISTANCE_DEVIATION)) { - std::stringstream error; - error << "Mapper Error: Smear deviation too small: Must be between " - << MIN_SMEAR_DISTANCE_DEVIATION << " and " - << MAX_SMEAR_DISTANCE_DEVIATION; - throw std::runtime_error(error.str()); - } - - // NOTE: Currently assumes a two-dimensional kernel - - // +1 for center - m_KernelSize = 2 * GetHalfKernelSize(m_SmearDeviation, resolution) + 1; - - // allocate kernel - m_pKernel = new uint8_t[m_KernelSize * m_KernelSize]; - if (m_pKernel == NULL) { - throw std::runtime_error("Unable to allocate memory for kernel!"); - } - - // calculate kernel - int32_t halfKernel = m_KernelSize / 2; - for (int32_t i = -halfKernel; i <= halfKernel; i++) { - for (int32_t j = -halfKernel; j <= halfKernel; j++) { -#ifdef WIN32 - double distanceFromMean = _hypot(i * resolution, j * resolution); -#else - double distanceFromMean = hypot(i * resolution, j * resolution); -#endif - double z = exp(-0.5 * pow(distanceFromMean / m_SmearDeviation, 2)); - - uint32_t kernelValue = - static_cast(amath::Round(z * GridStates_Occupied)); - assert(amath::IsUpTo(kernelValue, static_cast(255))); - - int kernelArrayIndex = - (i + halfKernel) + m_KernelSize * (j + halfKernel); - m_pKernel[kernelArrayIndex] = static_cast(kernelValue); - } - } - } - - /** - * Computes the kernel half-size based on the smear distance and the grid - * resolution. Computes to two standard deviations to get 95% region and to - * reduce aliasing. - * @param smearDeviation - * @param resolution - * @return kernel half-size based on the parameters - */ - static int32_t GetHalfKernelSize(double smearDeviation, double resolution) { - assert(resolution != 0.0); - - return static_cast(amath::Round(2.0 * smearDeviation / resolution)); - } - -private: - /** - * The point readings are smeared by this value in X and Y to create a - * smoother response. Default value is 0.03 meters. - */ - double m_SmearDeviation; - - // Size of one side of the kernel - int32_t m_KernelSize; - - // Cached kernel for smearing - uint8_t *m_pKernel; - - // region of interest - Rectangle2 m_Roi; -}; // CorrelationGrid - -#endif diff --git a/include/CustomData.h b/include/CustomData.h deleted file mode 100644 index 02b1ff0..0000000 --- a/include/CustomData.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef CUSTOM_DATA_H -#define CUSTOM_DATA_H -#include "Object.h" - -class CustomData : public Object -{ - public: - /** - * Constructor - */ - CustomData() - : Object() - { - } - - /** - * Destructor - */ - virtual ~CustomData() - { - } - -public: - /** - * Write out this custom data as a string - * @return string representation of this data object - */ - virtual const std::string Write() const = 0; - - /** - * Read in this custom data from a string - * @param rValue string representation of this data object - */ - virtual void Read(const std::string& rValue) = 0; - -private: - CustomData(const CustomData&); - const CustomData& operator=(const CustomData&); -}; - -/** - * Type declaration of CustomData vector - */ -typedef std::vector CustomDataVector; - -#endif diff --git a/include/Functor.h b/include/Functor.h deleted file mode 100644 index 9d8341f..0000000 --- a/include/Functor.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef FUNCTOR_H -#define FUNCTOR_H - -#include - -class Functor { -public: - /** - * Functor function - */ - virtual void operator()(int32_t){}; -}; // Functor - -#endif diff --git a/include/Grid.h b/include/Grid.h deleted file mode 100644 index c05d6cc..0000000 --- a/include/Grid.h +++ /dev/null @@ -1,358 +0,0 @@ -#ifndef GRID_H -#define GRID_H - -#include -#include -#include - -#include "AdditionalMath.h" -#include "Functor.h" -#include "CoordinateConverter.h" - -typedef enum - { - GridStates_Unknown = 0, - GridStates_Occupied = 100, - GridStates_Free = 255 - } GridStates; - -/** - * Defines a grid class - */ -template class Grid { -public: - /** - * Creates a grid of given size and resolution - * @param width - * @param height - * @param resolution - * @return grid pointer - */ - static Grid *CreateGrid(int32_t width, int32_t height, double resolution) { - Grid *pGrid = new Grid(width, height); - - pGrid->GetCoordinateConverter()->SetScale(1.0 / resolution); - - return pGrid; - } - - /** - * Destructor - */ - virtual ~Grid() { - delete[] m_pData; - delete m_pCoordinateConverter; - } - -public: - /** - * Clear out the grid data - */ - void Clear() { std::memset(m_pData, 0, GetDataSize() * sizeof(T)); } - - /** - * Returns a clone of this grid - * @return grid clone - */ - Grid *Clone() { - Grid *pGrid = CreateGrid(GetWidth(), GetHeight(), GetResolution()); - pGrid->GetCoordinateConverter()->SetOffset( - GetCoordinateConverter()->GetOffset()); - - memcpy(pGrid->GetDataPointer(), GetDataPointer(), GetDataSize()); - - return pGrid; - } - - /** - * Resizes the grid (deletes all old data) - * @param width - * @param height - */ - virtual void Resize(int32_t width, int32_t height) { - m_Width = width; - m_Height = height; - m_WidthStep = amath::AlignValue(width, 8); - - if (m_pData != NULL) { - delete[] m_pData; - m_pData = NULL; - } - - try { - m_pData = new T[GetDataSize()]; - - if (m_pCoordinateConverter == NULL) { - m_pCoordinateConverter = new CoordinateConverter(); - } - - m_pCoordinateConverter->SetSize(Size2(width, height)); - } catch (...) { - m_pData = NULL; - - m_Width = 0; - m_Height = 0; - m_WidthStep = 0; - } - - Clear(); - } - - /** - * Checks whether the given coordinates are valid grid indices - * @param rGrid - */ - inline bool IsValidGridIndex(const Vector2 &rGrid) const { - return (amath::IsUpTo(rGrid.GetX(), m_Width) && - amath::IsUpTo(rGrid.GetY(), m_Height)); - } - - /** - * Gets the index into the data pointer of the given grid coordinate - * @param rGrid - * @param boundaryCheck default value is true - * @return grid index - */ - virtual int32_t GridIndex(const Vector2 &rGrid, - bool boundaryCheck = true) const { - if (boundaryCheck == true) { - if (IsValidGridIndex(rGrid) == false) { - std::stringstream error; - error << "Index " << rGrid - << " out of range. Index must be between [0; " << m_Width - << ") and [0; " << m_Height << ")"; - std::cout << error.str() << std::endl; - throw error.str(); - } - } - - int32_t index = rGrid.GetX() + (rGrid.GetY() * m_WidthStep); - - if (boundaryCheck == true) { - assert(amath::IsUpTo(index, GetDataSize())); - } - - return index; - } - - /** - * Gets the grid coordinate from an index - * @param index - * @return grid coordinate - */ - Vector2 IndexToGrid(int32_t index) const { - Vector2 grid; - - grid.SetY(index / m_WidthStep); - grid.SetX(index - grid.GetY() * m_WidthStep); - - return grid; - } - - /** - * Converts the point from world coordinates to grid coordinates - * @param rWorld world coordinate - * @param flipY - * @return grid coordinate - */ - inline Vector2 WorldToGrid(const Vector2 &rWorld, - bool flipY = false) const { - return GetCoordinateConverter()->WorldToGrid(rWorld, flipY); - } - - /** - * Converts the point from grid coordinates to world coordinates - * @param rGrid world coordinate - * @param flipY - * @return world coordinate - */ - inline Vector2 GridToWorld(const Vector2 &rGrid, - bool flipY = false) const { - return GetCoordinateConverter()->GridToWorld(rGrid, flipY); - } - - /** - * Gets pointer to data at given grid coordinate - * @param rGrid grid coordinate - * @return grid point - */ - T *GetDataPointer(const Vector2 &rGrid) { - int32_t index = GridIndex(rGrid, true); - return m_pData + index; - } - - /** - * Gets pointer to data at given grid coordinate - * @param rGrid grid coordinate - * @return grid point - */ - T *GetDataPointer(const Vector2 &rGrid) const { - int32_t index = GridIndex(rGrid, true); - return m_pData + index; - } - - /** - * Gets the width of the grid - * @return width of the grid - */ - inline int32_t GetWidth() const { return m_Width; }; - - /** - * Gets the height of the grid - * @return height of the grid - */ - inline int32_t GetHeight() const { return m_Height; }; - - /** - * Get the size as a Size2 - * @return size of the grid - */ - inline const Size2 GetSize() const { - return Size2(m_Width, m_Height); - } - - /** - * Gets the width step in bytes - * @return width step - */ - inline int32_t GetWidthStep() const { return m_WidthStep; } - - /** - * Gets the grid data pointer - * @return data pointer - */ - inline T *GetDataPointer() { return m_pData; } - - /** - * Gets const grid data pointer - * @return data pointer - */ - inline T *GetDataPointer() const { return m_pData; } - - /** - * Gets the allocated grid size in bytes - * @return data size - */ - inline int32_t GetDataSize() const { return m_WidthStep * m_Height; } - - /** - * Get value at given grid coordinate - * @param rGrid grid coordinate - * @return value - */ - inline T GetValue(const Vector2 &rGrid) const { - int32_t index = GridIndex(rGrid); - return m_pData[index]; - } - - /** - * Gets the coordinate converter for this grid - * @return coordinate converter - */ - inline CoordinateConverter *GetCoordinateConverter() const { - return m_pCoordinateConverter; - } - - /** - * Gets the resolution - * @return resolution - */ - inline double GetResolution() const { - return GetCoordinateConverter()->GetResolution(); - } - - /** - * Gets the grids bounding box - * @return bounding box - */ - inline BoundingBox2 GetBoundingBox() const { - return GetCoordinateConverter()->GetBoundingBox(); - } - - /** - * Increments all the grid cells from (x0, y0) to (x1, y1); - * if applicable, apply f to each cell traced - * @param x0 - * @param y0 - * @param x1 - * @param y1 - * @param f - */ - void TraceLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, - Functor *f = NULL) { - bool steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - std::swap(x0, y0); - std::swap(x1, y1); - } - if (x0 > x1) { - std::swap(x0, x1); - std::swap(y0, y1); - } - - int32_t deltaX = x1 - x0; - int32_t deltaY = abs(y1 - y0); - int32_t error = 0; - int32_t ystep; - int32_t y = y0; - - if (y0 < y1) { - ystep = 1; - } else { - ystep = -1; - } - - int32_t pointX; - int32_t pointY; - for (int32_t x = x0; x <= x1; x++) { - if (steep) { - pointX = y; - pointY = x; - } else { - pointX = x; - pointY = y; - } - - error += deltaY; - - if (2 * error >= deltaX) { - y += ystep; - error -= deltaX; - } - - Vector2 gridIndex(pointX, pointY); - if (IsValidGridIndex(gridIndex)) { - int32_t index = GridIndex(gridIndex, false); - T *pGridPointer = GetDataPointer(); - pGridPointer[index]++; - - if (f != NULL) { - (*f)(index); - } - } - } - } - -protected: - /** - * Constructs grid of given size - * @param width - * @param height - */ - Grid(int32_t width, int32_t height) - : m_pData(NULL), m_pCoordinateConverter(NULL) { - Resize(width, height); - } - -private: - int32_t m_Width; // width of grid - int32_t m_Height; // height of grid - int32_t m_WidthStep; // 8 bit aligned width of grid - T *m_pData; // grid data - - // coordinate converter to convert between world coordinates and grid - // coordinates - CoordinateConverter *m_pCoordinateConverter; -}; // Grid - -#endif diff --git a/include/GridIndexLookup.h b/include/GridIndexLookup.h deleted file mode 100644 index 56d7425..0000000 --- a/include/GridIndexLookup.h +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef GRID_IDX_LKUP_H -#define GRID_IDX_LKUP_H -#include "Grid.h" -#include "LocalizedRangeScan.h" -#include "LookupArray.h" -#include "Transform.h" -#include -/** - * Create lookup tables for point readings at varying angles in grid. - * For each angle, grid indexes are calculated for each range reading. - * This is to speed up finding best angle/position for a localized range scan - * - * Used heavily in mapper and localizer. - * - * In the localizer, this is a huge speed up for calculating possible position. - * For each particle, a probability is calculated. The range scan is the same, - * but all grid indexes at all possible angles are calculated. So when - * calculating the particle probability at a specific angle, the index table is - * used to look up probability in probability grid! - * - */ -template class GridIndexLookup { -public: - /** - * Construct a GridIndexLookup with a grid - * @param pGrid - */ - GridIndexLookup(Grid *pGrid) - : m_pGrid(pGrid), m_Capacity(0), m_Size(0), m_ppLookupArray(NULL) {} - - /** - * Destructor - */ - virtual ~GridIndexLookup() { DestroyArrays(); } - -public: - /** - * Gets the lookup array for a particular angle index - * @param index - * @return lookup array - */ - const LookupArray *GetLookupArray(int32_t index) const { - assert(amath::IsUpTo(index, m_Size)); - - return m_ppLookupArray[index]; - } - - /** - * Get angles - * @return std::vector& angles - */ - const std::vector &GetAngles() const { return m_Angles; } - - /** - * Compute lookup table of the points of the given scan for the given angular - * space - * @param pScan the scan - * @param angleCenter - * @param angleOffset computes lookup arrays for the angles within this offset - * around angleStart - * @param angleResolution how fine a granularity to compute lookup arrays in - * the angular space - */ - void ComputeOffsets(LocalizedRangeScan *pScan, double angleCenter, - double angleOffset, double angleResolution) { - assert(angleOffset > 0.0); - assert(angleResolution > 0.0); - - - - int32_t nAngles = static_cast( - amath::Round(angleOffset * 2.0 / angleResolution) + 1); - - SetSize(nAngles); - - - ////////////////////////////////////////////////////// - // convert points into local coordinates of scan pose - - const PointVectorDouble &rPointReadings = pScan->GetPointReadings(); - - - // compute transform to scan pose - Transform transform(pScan->GetCorrectedPose()); - - - Pose2Vector localPoints; - for (auto iter : rPointReadings) { - // do inverse transform to get points in local coordinates - Pose2 vec = transform.InverseTransformPose(Pose2(iter, 0.0)); - localPoints.push_back(vec); - } - - - - ////////////////////////////////////////////////////// - // create lookup array for different angles - double angle = 0.0; - double startAngle = angleCenter - angleOffset; - for (int32_t angleIndex = 0; angleIndex < nAngles; angleIndex++) { - angle = startAngle + angleIndex * angleResolution; - ComputeOffsets(angleIndex, angle, localPoints, pScan); - } - - // assert(amath::DoubleEqual(angle, angleCenter + angleOffset)); - } - -private: - /** - * Compute lookup value of points for given angle - * @param angleIndex - * @param angle - * @param rLocalPoints - */ - void ComputeOffsets(int32_t angleIndex, double angle, - const Pose2Vector &rLocalPoints, - LocalizedRangeScan *pScan) { - m_ppLookupArray[angleIndex]->SetSize( - static_cast(rLocalPoints.size())); - m_Angles.at(angleIndex) = angle; - - // set up point array by computing relative offsets to points readings - // when rotated by given angle - - const Vector2 &rGridOffset = - m_pGrid->GetCoordinateConverter()->GetOffset(); - - double cosine = cos(angle); - double sine = sin(angle); - - int32_t readingIndex = 0; - - int32_t *pAngleIndexPointer = - m_ppLookupArray[angleIndex]->GetArrayPointer(); - - double maxRange = pScan->GetMaximumRange(); - - for (auto iter : rLocalPoints) { - const Vector2 &rPosition = iter.GetPosition(); - - if (std::isnan(pScan->GetRangeReadings()[readingIndex]) || - std::isinf(pScan->GetRangeReadings()[readingIndex])) { - pAngleIndexPointer[readingIndex] = INVALID_SCAN; - readingIndex++; - continue; - } - - // counterclockwise rotation and that rotation is about the origin (0, 0). - Vector2 offset; - offset.SetX(cosine * rPosition.GetX() - sine * rPosition.GetY()); - offset.SetY(sine * rPosition.GetX() + cosine * rPosition.GetY()); - - // have to compensate for the grid offset when getting the grid index - Vector2 gridPoint = m_pGrid->WorldToGrid(offset + rGridOffset); - - // use base GridIndex to ignore ROI - int32_t lookupIndex = m_pGrid->Grid::GridIndex(gridPoint, false); - - pAngleIndexPointer[readingIndex] = lookupIndex; - - readingIndex++; - } - assert(readingIndex == rLocalPoints.size()); - } - - /** - * Sets size of lookup table (resize if not big enough) - * @param size - */ - void SetSize(int32_t size) { - assert(size > 0); - - if (size > m_Capacity) { - if (m_ppLookupArray != NULL) { - DestroyArrays(); - } - - m_Capacity = size; - m_ppLookupArray = new LookupArray *[m_Capacity]; - for (int32_t i = 0; i < m_Capacity; i++) { - m_ppLookupArray[i] = new LookupArray(); - } - } - - m_Size = size; - - m_Angles.resize(size); - } - - /** - * Delete the arrays - */ - void DestroyArrays() { - for (int32_t i = 0; i < m_Capacity; i++) { - delete m_ppLookupArray[i]; - } - - delete[] m_ppLookupArray; - m_ppLookupArray = NULL; - } - -private: - Grid *m_pGrid; - - int32_t m_Capacity; - int32_t m_Size; - - LookupArray **m_ppLookupArray; - - // for sanity check - std::vector m_Angles; -}; // class GridIndexLookup - -#endif diff --git a/include/LocalizedRangeScan.h b/include/LocalizedRangeScan.h deleted file mode 100644 index 241eda5..0000000 --- a/include/LocalizedRangeScan.h +++ /dev/null @@ -1,398 +0,0 @@ -#ifndef LOCALIZED_RANGE_SCAN_H -#define LOCALIZED_RANGE_SCAN_H - -#include -#include -#include - -#include "Transform.h" -#include "Vector2.h" -#include "AdditionalMath.h" -#include "CoordinateConverter.h" -#include "AdditionalMath.h" - -#include -#include -#include - -#include "Name.h" -#include "SensorData.h" -#include "LocalizedRangeScan.h" - -/** - * Type declaration of range readings vector - */ -typedef std::vector RangeReadingsVector; - -struct LaserScanConfig { - double minAngle; - double maxAngle; - double angularResolution; - double minRange; - double maxRange; - double rangeThreshold; - std::string sensorName; -}; - -/** - * LaserRangeScan representing the range readings from a laser range finder - * sensor. - */ -class LaserRangeScan : public SensorData { -public: - /** - * Constructs a scan from the given sensor with the given readings - * @param rSensorName - * @param rRangeReadings - */ - LaserRangeScan(const LaserScanConfig &_config, - const RangeReadingsVector &rRangeReadings) - : SensorData(_config.sensorName), config(_config), m_pRangeReadings(NULL), - m_NumberOfRangeReadings(0) { - - SetRangeReadings(rRangeReadings); - } - - /** - * Destructor - */ - virtual ~LaserRangeScan() { delete[] m_pRangeReadings; } - -public: - LaserScanConfig config; - /** - * Gets the range readings of this scan - * @return range readings of this scan - */ - inline double *GetRangeReadings() const { return m_pRangeReadings; } - - inline RangeReadingsVector GetRangeReadingsVector() const { - return RangeReadingsVector(m_pRangeReadings, - m_pRangeReadings + m_NumberOfRangeReadings); - } - - /** - * Sets the range readings for this scan - * @param rRangeReadings - */ - inline void SetRangeReadings(const RangeReadingsVector &rRangeReadings) { - // ignore for now! XXXMAE BUGUBUG 05/21/2010 << TODO(lucbettaieb): What the - // heck is this?? if (rRangeReadings.size() != GetNumberOfRangeReadings()) - // { - // std::stringstream error; - // error << "Given number of readings (" << rRangeReadings.size() - // << ") does not match expected number of range finder (" << - // GetNumberOfRangeReadings() << ")"; - // throw Exception(error.str()); - // } - - if (!rRangeReadings.empty()) { - if (rRangeReadings.size() != m_NumberOfRangeReadings) { - // delete old readings - delete[] m_pRangeReadings; - - // store size of array! - m_NumberOfRangeReadings = static_cast(rRangeReadings.size()); - - // allocate range readings - m_pRangeReadings = new double[m_NumberOfRangeReadings]; - } - - // copy readings - int32_t index = 0; - for (auto iter : rRangeReadings) { - m_pRangeReadings[index++] = iter; - } - - } else { - delete[] m_pRangeReadings; - m_pRangeReadings = NULL; - } - } - - /** - * Gets the number of range readings - * @return number of range readings - */ - inline int32_t GetNumberOfRangeReadings() const { - return m_NumberOfRangeReadings; - } - - /** - * Gets this range finder sensor's minimum range - * @return minimum range - */ - inline double GetMinimumRange() const { return config.minRange; } - - /** - * Gets this range finder sensor's maximum range - * @return maximum range - */ - inline double GetMaximumRange() { return config.maxRange; } - - /** - * Gets the range threshold - * @return range threshold - */ - inline double GetRangeThreshold() const { return config.rangeThreshold; } - - /** - * Gets this range finder sensor's minimum angle - * @return minimum angle - */ - inline double GetMinimumAngle() const { return config.minAngle; } - - /** - * Gets this range finder sensor's maximum angle - * @return maximum angle - */ - inline double GetMaximumAngle() const { return config.maxAngle; } - - /** - * Gets this range finder sensor's angular resolution - * @return angular resolution - */ - inline double GetAngularResolution() const { return config.angularResolution; } - -private: - LaserRangeScan(const LaserRangeScan &); - const LaserRangeScan &operator=(const LaserRangeScan &); - -private: - double *m_pRangeReadings; - int32_t m_NumberOfRangeReadings; -}; // LaserRangeScan - -/** - * The LocalizedRangeScan contains range data from a single sweep of a laser - * range finder sensor in a two-dimensional space and position information. The - * odometer position is the position reported by the robot when the range data - * was recorded. The corrected position is the position calculated by the mapper - * (or localizer) - */ -class LocalizedRangeScan : public LaserRangeScan { -public: - /** - * Constructs a range scan from the given range finder with the given - * readings - */ - LocalizedRangeScan(const LaserScanConfig &_config, - const RangeReadingsVector &rReadings, - Pose2 _odomPose, Pose2 _correctedPose, uint32_t _uniqueId, double _scanTime) - : LaserRangeScan(_config, rReadings), m_IsDirty(true) { - SetOdometricPose(_odomPose); - SetCorrectedPose(_correctedPose); - SetUniqueId(_uniqueId); - SetTime(_scanTime); - } - - /** - * Destructor - */ - virtual ~LocalizedRangeScan() {} - -private: - mutable std::shared_timed_mutex m_Lock; - -public: - /** - * Gets the odometric pose of this scan - * @return odometric pose of this scan - */ - inline const Pose2 &GetOdometricPose() const { return m_OdometricPose; } - - /** - * Sets the odometric pose of this scan - * @param rPose - */ - inline void SetOdometricPose(const Pose2 &rPose) { m_OdometricPose = rPose; } - - /** - * Gets the (possibly corrected) robot pose at which this scan was taken. The - * corrected robot pose of the scan is usually set by an external module such - * as a localization or mapping module when it is determined that the original - * pose was incorrect. The external module will set the correct pose based on - * additional sensor data and any context information it has. If the pose has - * not been corrected, a call to this method returns the same pose as - * GetOdometricPose(). - * @return corrected pose - */ - inline const Pose2 &GetCorrectedPose() const { return m_CorrectedPose; } - - /** - * Moves the scan by moving the robot pose to the given location. - * @param rPose new pose of the robot of this scan - */ - inline void SetCorrectedPose(const Pose2 &rPose) { - m_CorrectedPose = rPose; - - m_IsDirty = true; - } - - /** - * Gets barycenter of point readings - */ - inline const Pose2 &GetBarycenterPose() const { - std::shared_lock lock(m_Lock); - if (m_IsDirty) { - // throw away constness and do an update! - lock.unlock(); - std::unique_lock uniqueLock(m_Lock); - const_cast(this)->Update(); - } - - return m_BarycenterPose; - } - - /** - * Gets the bounding box of this scan - * @return bounding box of this scan - */ - inline const BoundingBox2 &GetBoundingBox() const { - std::shared_lock lock(m_Lock); - if (m_IsDirty) { - // throw away constness and do an update! - lock.unlock(); - std::unique_lock uniqueLock(m_Lock); - const_cast(this)->Update(); - } - - return m_BoundingBox; - } - - /** - * Get point readings in local coordinates - */ - inline const PointVectorDouble & - GetPointReadings(bool wantFiltered = false) const { - std::shared_lock lock(m_Lock); - if (m_IsDirty) { - // throw away constness and do an update! - lock.unlock(); - std::unique_lock uniqueLock(m_Lock); - const_cast(this)->Update(); - } - - if (wantFiltered == true) { - return m_PointReadings; - } else { - return m_UnfilteredPointReadings; - } - } - -private: - /** - * Compute point readings based on range readings - * Only range readings within [minimum range; range threshold] are returned - */ - virtual void Update() { - if (true) { - m_PointReadings.clear(); - m_UnfilteredPointReadings.clear(); - - double rangeThreshold = this->GetRangeThreshold(); - double minimumAngle = this->GetMinimumAngle(); - double angularResolution = this->GetAngularResolution(); - Pose2 scanPose = GetCorrectedPose(); - - // compute point readings - Vector2 rangePointsSum; - uint32_t beamNum = 0; - for (uint32_t i = 0; i < this->GetNumberOfRangeReadings(); - i++, beamNum++) { - double rangeReading = GetRangeReadings()[i]; - if (!amath::InRange(rangeReading, this->GetMinimumRange(), - rangeThreshold)) { - double angle = scanPose.GetHeading() + minimumAngle + - beamNum * angularResolution; - - Vector2 point; - point.SetX(scanPose.GetX() + (rangeReading * cos(angle))); - point.SetY(scanPose.GetY() + (rangeReading * sin(angle))); - - m_UnfilteredPointReadings.push_back(point); - continue; - } - - double angle = - scanPose.GetHeading() + minimumAngle + beamNum * angularResolution; - - Vector2 point; - point.SetX(scanPose.GetX() + (rangeReading * cos(angle))); - point.SetY(scanPose.GetY() + (rangeReading * sin(angle))); - - m_PointReadings.push_back(point); - m_UnfilteredPointReadings.push_back(point); - - rangePointsSum += point; - } - - // compute barycenter - double nPoints = static_cast(m_PointReadings.size()); - if (nPoints != 0.0) { - Vector2 averagePosition = - Vector2(rangePointsSum / nPoints); - m_BarycenterPose = Pose2(averagePosition, 0.0); - } else { - m_BarycenterPose = scanPose; - } - - // calculate bounding box of scan - m_BoundingBox = BoundingBox2(); - m_BoundingBox.Add(scanPose.GetPosition()); - for (auto iter : m_PointReadings) { - m_BoundingBox.Add(iter); - } - } - - m_IsDirty = false; - } - -private: - LocalizedRangeScan(const LocalizedRangeScan &); - const LocalizedRangeScan &operator=(const LocalizedRangeScan &); - -private: - /** - * Odometric pose of robot - */ - Pose2 m_OdometricPose; - - /** - * Corrected pose of robot calculated by mapper (or localizer) - */ - Pose2 m_CorrectedPose; - -protected: - /** - * Average of all the point readings - */ - Pose2 m_BarycenterPose; - - /** - * Vector of point readings - */ - PointVectorDouble m_PointReadings; - - /** - * Vector of unfiltered point readings - */ - PointVectorDouble m_UnfilteredPointReadings; - - /** - * Bounding box of localized range scan - */ - BoundingBox2 m_BoundingBox; - - /** - * Internal flag used to update point readings, barycenter and bounding box - */ - bool m_IsDirty; -}; // LocalizedRangeScan - -/** - * Type declaration of LocalizedRangeScan vector - */ -typedef std::vector LocalizedRangeScanVector; - -#endif diff --git a/include/LookupArray.h b/include/LookupArray.h deleted file mode 100644 index 6df0e45..0000000 --- a/include/LookupArray.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef LOOKUPARRAY_H -#define LOOKUPARRAY_H - -#include -#include -#include - -class LookupArray { -public: - /** - * Constructs lookup array - */ - LookupArray() : m_pArray(NULL), m_Capacity(0), m_Size(0) {} - - /** - * Destructor - */ - virtual ~LookupArray() { - assert(m_pArray != NULL); - - delete[] m_pArray; - m_pArray = NULL; - } - -public: - /** - * Clear array - */ - void Clear() { memset(m_pArray, 0, sizeof(int32_t) * m_Capacity); } - - /** - * Gets size of array - * @return array size - */ - int32_t GetSize() const { return m_Size; } - - /** - * Sets size of array (resize if not big enough) - * @param size - */ - void SetSize(int32_t size) { - assert(size != 0); - - if (size > m_Capacity) { - if (m_pArray != NULL) { - delete[] m_pArray; - } - m_Capacity = size; - m_pArray = new int32_t[m_Capacity]; - } - - m_Size = size; - } - - /** - * Gets reference to value at given index - * @param index - * @return reference to value at index - */ - inline int32_t &operator[](int32_t index) { - assert(index < m_Size); - - return m_pArray[index]; - } - - /** - * Gets value at given index - * @param index - * @return value at index - */ - inline int32_t operator[](int32_t index) const { - assert(index < m_Size); - - return m_pArray[index]; - } - - /** - * Gets array pointer - * @return array pointer - */ - inline int32_t *GetArrayPointer() { return m_pArray; } - - /** - * Gets array pointer - * @return array pointer - */ - inline int32_t *GetArrayPointer() const { return m_pArray; } - -private: - int32_t *m_pArray; - int32_t m_Capacity; - int32_t m_Size; -}; // LookupArray - -#endif diff --git a/include/Matrix.h b/include/Matrix.h deleted file mode 100644 index 199c12b..0000000 --- a/include/Matrix.h +++ /dev/null @@ -1,378 +0,0 @@ -#ifndef MATRIX_H -#define MATRIX_H - -#include -#include -#include -#include -#include - -#include "AdditionalMath.h" -#include "Pose.h" - -class Matrix3 { -public: - /** - * Default constructor - */ - Matrix3() { Clear(); } - - /** - * Copy constructor - */ - inline Matrix3(const Matrix3 &rOther) { - std::memcpy(m_Matrix, rOther.m_Matrix, 9 * sizeof(double)); - } - -public: - /** - * Sets this matrix to identity matrix - */ - void SetToIdentity() { - std::memset(m_Matrix, 0, 9 * sizeof(double)); - - for (int32_t i = 0; i < 3; i++) { - m_Matrix[i][i] = 1.0; - } - } - - /** - * Sets this matrix to zero matrix - */ - void Clear() { memset(m_Matrix, 0, 9 * sizeof(double)); } - - /** - * Sets this matrix to be the rotation matrix of rotation around given axis - * @param x x-coordinate of axis - * @param y y-coordinate of axis - * @param z z-coordinate of axis - * @param radians amount of rotation - */ - void FromAxisAngle(double x, double y, double z, const double radians) { - double cosRadians = cos(radians); - double sinRadians = sin(radians); - double oneMinusCos = 1.0 - cosRadians; - - double xx = x * x; - double yy = y * y; - double zz = z * z; - - double xyMCos = x * y * oneMinusCos; - double xzMCos = x * z * oneMinusCos; - double yzMCos = y * z * oneMinusCos; - - double xSin = x * sinRadians; - double ySin = y * sinRadians; - double zSin = z * sinRadians; - - m_Matrix[0][0] = xx * oneMinusCos + cosRadians; - m_Matrix[0][1] = xyMCos - zSin; - m_Matrix[0][2] = xzMCos + ySin; - - m_Matrix[1][0] = xyMCos + zSin; - m_Matrix[1][1] = yy * oneMinusCos + cosRadians; - m_Matrix[1][2] = yzMCos - xSin; - - m_Matrix[2][0] = xzMCos - ySin; - m_Matrix[2][1] = yzMCos + xSin; - m_Matrix[2][2] = zz * oneMinusCos + cosRadians; - } - - /** - * Returns transposed version of this matrix - * @return transposed matrix - */ - Matrix3 Transpose() const { - Matrix3 transpose; - - for (uint32_t row = 0; row < 3; row++) { - for (uint32_t col = 0; col < 3; col++) { - transpose.m_Matrix[row][col] = m_Matrix[col][row]; - } - } - - return transpose; - } - - /** - * Returns the inverse of the matrix - */ - Matrix3 Inverse() const { - Matrix3 kInverse = *this; - bool haveInverse = InverseFast(kInverse, 1e-14); - if (haveInverse == false) { - assert(false); - } - return kInverse; - } - - /** - * Internal helper method for inverse matrix calculation - * This code is lifted from the OgreMatrix3 class!! - */ - bool InverseFast(Matrix3 &rkInverse, - double fTolerance = KT_TOLERANCE) const { - // Invert a 3x3 using cofactors. This is about 8 times faster than - // the Numerical Recipes code which uses Gaussian elimination. - rkInverse.m_Matrix[0][0] = - m_Matrix[1][1] * m_Matrix[2][2] - m_Matrix[1][2] * m_Matrix[2][1]; - rkInverse.m_Matrix[0][1] = - m_Matrix[0][2] * m_Matrix[2][1] - m_Matrix[0][1] * m_Matrix[2][2]; - rkInverse.m_Matrix[0][2] = - m_Matrix[0][1] * m_Matrix[1][2] - m_Matrix[0][2] * m_Matrix[1][1]; - rkInverse.m_Matrix[1][0] = - m_Matrix[1][2] * m_Matrix[2][0] - m_Matrix[1][0] * m_Matrix[2][2]; - rkInverse.m_Matrix[1][1] = - m_Matrix[0][0] * m_Matrix[2][2] - m_Matrix[0][2] * m_Matrix[2][0]; - rkInverse.m_Matrix[1][2] = - m_Matrix[0][2] * m_Matrix[1][0] - m_Matrix[0][0] * m_Matrix[1][2]; - rkInverse.m_Matrix[2][0] = - m_Matrix[1][0] * m_Matrix[2][1] - m_Matrix[1][1] * m_Matrix[2][0]; - rkInverse.m_Matrix[2][1] = - m_Matrix[0][1] * m_Matrix[2][0] - m_Matrix[0][0] * m_Matrix[2][1]; - rkInverse.m_Matrix[2][2] = - m_Matrix[0][0] * m_Matrix[1][1] - m_Matrix[0][1] * m_Matrix[1][0]; - - double fDet = m_Matrix[0][0] * rkInverse.m_Matrix[0][0] + - m_Matrix[0][1] * rkInverse.m_Matrix[1][0] + - m_Matrix[0][2] * rkInverse.m_Matrix[2][0]; - - if (fabs(fDet) <= fTolerance) { - return false; - } - - double fInvDet = 1.0 / fDet; - for (size_t row = 0; row < 3; row++) { - for (size_t col = 0; col < 3; col++) { - rkInverse.m_Matrix[row][col] *= fInvDet; - } - } - - return true; - } - - /** - * Returns a string representation of this matrix - * @return string representation of this matrix - */ - inline std::string ToString() const { - std::stringstream converter; - converter.precision(std::numeric_limits::digits10); - - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - converter << m_Matrix[row][col] << " "; - } - } - - return converter.str(); - } - -public: - /** - * Assignment operator - */ - inline Matrix3 &operator=(const Matrix3 &rOther) { - std::memcpy(m_Matrix, rOther.m_Matrix, 9 * sizeof(double)); - return *this; - } - - /** - * Matrix element access, allows use of construct mat(r, c) - * @param row - * @param column - * @return reference to mat(r,c) - */ - inline double &operator()(uint32_t row, uint32_t column) { - return m_Matrix[row][column]; - } - - /** - * Read-only matrix element access, allows use of construct mat(r, c) - * @param row - * @param column - * @return mat(r,c) - */ - inline double operator()(uint32_t row, uint32_t column) const { - return m_Matrix[row][column]; - } - - /** - * Binary Matrix3 multiplication. - * @param rOther - * @return Matrix3 product - */ - Matrix3 operator*(const Matrix3 &rOther) const { - Matrix3 product; - - for (size_t row = 0; row < 3; row++) { - for (size_t col = 0; col < 3; col++) { - product.m_Matrix[row][col] = - m_Matrix[row][0] * rOther.m_Matrix[0][col] + - m_Matrix[row][1] * rOther.m_Matrix[1][col] + - m_Matrix[row][2] * rOther.m_Matrix[2][col]; - } - } - - return product; - } - - /** - * Matrix3 and Pose2 multiplication - matrix * pose [3x3 * 3x1 = 3x1] - * @param rPose2 - * @return Pose2 product - */ - inline Pose2 operator*(const Pose2 &rPose2) const { - Pose2 pose2; - - pose2.SetX(m_Matrix[0][0] * rPose2.GetX() + m_Matrix[0][1] * rPose2.GetY() + - m_Matrix[0][2] * rPose2.GetHeading()); - pose2.SetY(m_Matrix[1][0] * rPose2.GetX() + m_Matrix[1][1] * rPose2.GetY() + - m_Matrix[1][2] * rPose2.GetHeading()); - pose2.SetHeading(m_Matrix[2][0] * rPose2.GetX() + - m_Matrix[2][1] * rPose2.GetY() + - m_Matrix[2][2] * rPose2.GetHeading()); - - return pose2; - } - - /** - * In place Matrix3 add. - * @param rkMatrix - */ - inline void operator+=(const Matrix3 &rkMatrix) { - for (uint32_t row = 0; row < 3; row++) { - for (uint32_t col = 0; col < 3; col++) { - m_Matrix[row][col] += rkMatrix.m_Matrix[row][col]; - } - } - } - - /** - * Write Matrix3 onto output stream - * @param rStream output stream - * @param rMatrix to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Matrix3 &rMatrix) { - rStream << rMatrix.ToString(); - return rStream; - } - -// private: - double m_Matrix[3][3]; -}; // Matrix3 - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -/** - * Defines a general Matrix class. - */ -class Matrix { -public: - /** - * Constructs a matrix of size rows x columns - */ - Matrix(uint32_t rows, uint32_t columns) - : m_Rows(rows), m_Columns(columns), m_pData(NULL) { - Allocate(); - - Clear(); - } - - /** - * Destructor - */ - virtual ~Matrix() { delete[] m_pData; } - -public: - /** - * Set all entries to 0 - */ - void Clear() { - if (m_pData != NULL) { - memset(m_pData, 0, sizeof(double) * m_Rows * m_Columns); - } - } - - /** - * Gets the number of rows of the matrix - * @return nubmer of rows - */ - inline uint32_t GetRows() const { return m_Rows; } - - /** - * Gets the number of columns of the matrix - * @return nubmer of columns - */ - inline uint32_t GetColumns() const { return m_Columns; } - - /** - * Returns a reference to the entry at (row,column) - * @param row - * @param column - * @return reference to entry at (row,column) - */ - inline double &operator()(uint32_t row, uint32_t column) { - RangeCheck(row, column); - - return m_pData[row + column * m_Rows]; - } - - /** - * Returns a const reference to the entry at (row,column) - * @param row - * @param column - * @return const reference to entry at (row,column) - */ - inline const double &operator()(uint32_t row, uint32_t column) const { - RangeCheck(row, column); - - return m_pData[row + column * m_Rows]; - } - -private: - /** - * Allocate space for the matrix - */ - void Allocate() { - try { - if (m_pData != NULL) { - delete[] m_pData; - } - - m_pData = new double[m_Rows * m_Columns]; - } catch (const std::bad_alloc &ex) { - throw "Matrix allocation error"; - } - - if (m_pData == NULL) { - throw "Matrix allocation error"; - } - } - - /** - * Checks if (row,column) is a valid entry into the matrix - * @param row - * @param column - */ - inline void RangeCheck(uint32_t row, uint32_t column) const { - if (amath::IsUpTo(row, m_Rows) == false) { - throw "Matrix - RangeCheck ERROR!!!!"; - } - - if (amath::IsUpTo(column, m_Columns) == false) { - throw "Matrix - RangeCheck ERROR!!!!"; - } - } - -private: - uint32_t m_Rows; - uint32_t m_Columns; - - double *m_pData; -}; // Matrix - -#endif diff --git a/include/Name.h b/include/Name.h deleted file mode 100644 index 2d412c1..0000000 --- a/include/Name.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef NAME_H -#define NAME_H - -#include - -class Name { -public: - /** - * Constructor - */ - Name() {} - - /** - * Constructor - */ - Name(const std::string &rName) { Parse(rName); } - - /** - * Constructor - */ - Name(const Name &rOther) : m_Name(rOther.m_Name), m_Scope(rOther.m_Scope) {} - - /** - * Destructor - */ - virtual ~Name() {} - -public: - /** - * Gets the name of this name - * @return name - */ - inline const std::string &GetName() const { return m_Name; } - - /** - * Sets the name - * @param rName name - */ - inline void SetName(const std::string &rName) { - std::string::size_type pos = rName.find_last_of('/'); - if (pos != 0 && pos != std::string::npos) { - throw "Name can't contain a scope!"; - } - - m_Name = rName; - } - - /** - * Gets the scope of this name - * @return scope - */ - inline const std::string &GetScope() const { return m_Scope; } - - /** - * Sets the scope of this name - * @param rScope scope - */ - inline void SetScope(const std::string &rScope) { m_Scope = rScope; } - - /** - * Returns a string representation of this name - * @return string representation of this name - */ - inline std::string ToString() const { - if (m_Scope == "") { - return m_Name; - } else { - std::string name; - name.append("/"); - name.append(m_Scope); - name.append("/"); - name.append(m_Name); - - return name; - } - } - -public: - /** - * Assignment operator. - */ - Name &operator=(const Name &rOther) { - if (&rOther != this) { - m_Name = rOther.m_Name; - m_Scope = rOther.m_Scope; - } - - return *this; - } - - /** - * Equality operator. - */ - bool operator==(const Name &rOther) const { - return (m_Name == rOther.m_Name) && (m_Scope == rOther.m_Scope); - } - - /** - * Inequality operator. - */ - bool operator!=(const Name &rOther) const { return !(*this == rOther); } - - /** - * Less than operator. - */ - bool operator<(const Name &rOther) const { - return ToString() < rOther.ToString(); - } - - /** - * Write Name onto output stream - * @param rStream output stream - * @param rName to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Name &rName) { - rStream << rName.ToString(); - return rStream; - } - -private: - /** - * Parse the given string into a Name object - * @param rName name - */ - void Parse(const std::string &rName) { - std::string::size_type pos = rName.find_last_of('/'); - - if (pos == std::string::npos) { - m_Name = rName; - } else { - m_Scope = rName.substr(0, pos); - m_Name = rName.substr(pos + 1, rName.size()); - - // remove '/' from m_Scope if first!! - if (m_Scope.size() > 0 && m_Scope[0] == '/') { - m_Scope = m_Scope.substr(1, m_Scope.size()); - } - } - } - - /** - * Validates the given string as a Name - * @param rName name - */ - void Validate(const std::string &rName) { - if (rName.empty()) { - return; - } - - char c = rName[0]; - if (IsValidFirst(c)) { - for (size_t i = 1; i < rName.size(); ++i) { - c = rName[i]; - if (!IsValid(c)) { - throw "Invalid character in name. Valid characters must be " - "within the ranges A-Z, a-z, 0-9, '/', '_' and '-'."; - } - } - } else { - throw "Invalid first character in name. Valid characters must " - "be within the ranges A-Z, a-z, and '/'."; - } - } - - /** - * Whether the character is valid as a first character (alphanumeric or /) - * @param c character - * @return true if the character is a valid first character - */ - inline bool IsValidFirst(char c) { return (isalpha(c) || c == '/'); } - - /** - * Whether the character is a valid character (alphanumeric, /, _, or -) - * @param c character - * @return true if the character is valid - */ - inline bool IsValid(char c) { - return (isalnum(c) || c == '/' || c == '_' || c == '-'); - } - -private: - std::string m_Name; - std::string m_Scope; -}; - -#endif diff --git a/include/Object.h b/include/Object.h deleted file mode 100644 index 7323f31..0000000 --- a/include/Object.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef OBJECT_H -#define OBJECT_H - -#include "Name.h" -#include - -class NonCopyable { -private: - NonCopyable(const NonCopyable &); - const NonCopyable &operator=(const NonCopyable &); - -protected: - NonCopyable() {} - - virtual ~NonCopyable() {} -}; // class NonCopyable - -/** - * Abstract base class for Karto objects. - */ -class Object : public NonCopyable { -public: - /** - * Default constructor - */ - Object(); - - /** - * Constructs an object with the given name - * @param rName - */ - Object(const Name &rName); - - /** - * Default constructor - */ - virtual ~Object(); - -public: - /** - * Gets the name of this object - * @return name - */ - inline const Name &GetName() const { return m_Name; } - - /** - * Gets the class name of this object - * @return class name - */ - // virtual const char *GetClassName() const = 0; - - /** - * Gets the type of this object - * @return object type - */ - // virtual kt_objecttype GetObjectType() const = 0; - - // /** - // * Gets the parameter manager of this dataset - // * @return parameter manager - // */ - // virtual inline ParameterManager *GetParameterManager() { - // return m_pParameterManager; - // } - - /** - * Gets the named parameter - * @param rName name of parameter - * @return parameter - */ - // inline AbstractParameter *GetParameter(const std::string &rName) const { - // return m_pParameterManager->Get(rName); - // } - - /** - * Sets the parameter with the given name with the given value - * @param rName name - * @param value value - */ - template - inline void SetParameter(const std::string &rName, T value); - - /** - * Gets all parameters - * @return parameters - */ - // inline const ParameterVector &GetParameters() const { - // return m_pParameterManager->GetParameterVector(); - // } - -private: - Object(const Object &); - const Object &operator=(const Object &); - -private: - Name m_Name; - // ParameterManager *m_pParameterManager; -}; - -/** - * Type declaration of Object vector - */ -typedef std::vector ObjectVector; - -#endif diff --git a/include/OccupancyGrid.h b/include/OccupancyGrid.h deleted file mode 100644 index 5c7a55c..0000000 --- a/include/OccupancyGrid.h +++ /dev/null @@ -1,439 +0,0 @@ -#ifndef OCCUPANCY_GRID_H -#define OCCUPANCY_GRID_H - -#include "Vector2.h" -#include "Grid.h" -#include "Functor.h" -#include "CoordinateConverter.h" -#include "LocalizedRangeScan.h" -#include "AdditionalMath.h" - -class OccupancyGrid; - -class CellUpdater : public Functor { -public: - CellUpdater(OccupancyGrid *pGrid) : m_pOccupancyGrid(pGrid) {} - - /** - * Updates the cell at the given index based on the grid's hits and pass - * counters - * @param index - */ - virtual void operator()(uint32_t index); - -private: - OccupancyGrid *m_pOccupancyGrid; -}; // CellUpdater - -/** - * Occupancy grid definition. See GridStates for possible grid values. - */ -class OccupancyGrid : public Grid { - friend class CellUpdater; - friend class IncrementalOccupancyGrid; - -public: - /** - * Constructs an occupancy grid of given size - * @param width - * @param height - * @param rOffset - * @param resolution - */ - OccupancyGrid(int32_t width, int32_t height, - const Vector2 &rOffset, - double resolution, - uint32_t minPassThrough = 2, - double occupancyThreshold = 0.1, - double _rangeThreshold = 0) - : Grid(width, height), - m_pCellPassCnt(Grid::CreateGrid(0, 0, resolution)), - m_pCellHitsCnt(Grid::CreateGrid(0, 0, resolution)), - m_pCellUpdater(NULL), rangeThreshold(_rangeThreshold) { - m_pCellUpdater = new CellUpdater(this); - - // TODO Exceptions? - // if (karto::math::DoubleEqual(resolution, 0.0)) { - // throw Exception("Resolution cannot be 0"); - // } - - m_pMinPassThrough = minPassThrough; - m_pOccupancyThreshold = occupancyThreshold; - - GetCoordinateConverter()->SetScale(1.0 / resolution); - GetCoordinateConverter()->SetOffset(rOffset); - } - - /** - * Destructor - */ - virtual ~OccupancyGrid() { - delete m_pCellUpdater; - delete m_pCellPassCnt; - delete m_pCellHitsCnt; - } - -public: - /** - * Create an occupancy grid from the given scans using the given resolution - * @param rScans - * @param resolution - */ - static OccupancyGrid *CreateFromScans(const LocalizedRangeScanVector &rScans, - double resolution, double rangeThreshold) { - if (rScans.empty()) { - return NULL; - } - - int32_t width, height; - Vector2 offset; - ComputeDimensions(rScans, resolution, width, height, offset); - OccupancyGrid *pOccupancyGrid = - new OccupancyGrid(width, height, offset, resolution); - pOccupancyGrid->rangeThreshold = rangeThreshold; - pOccupancyGrid->CreateFromScans(rScans); - - return pOccupancyGrid; - } - - /** - * Make a clone - * @return occupancy grid clone - */ - OccupancyGrid *Clone() const { - OccupancyGrid *pOccupancyGrid = new OccupancyGrid( - GetWidth(), GetHeight(), GetCoordinateConverter()->GetOffset(), - 1.0 / GetCoordinateConverter()->GetScale()); - memcpy(pOccupancyGrid->GetDataPointer(), GetDataPointer(), GetDataSize()); - - pOccupancyGrid->GetCoordinateConverter()->SetSize( - GetCoordinateConverter()->GetSize()); - pOccupancyGrid->m_pCellPassCnt = m_pCellPassCnt->Clone(); - pOccupancyGrid->m_pCellHitsCnt = m_pCellHitsCnt->Clone(); - - return pOccupancyGrid; - } - - /** - * Check if grid point is free - * @param rPose - * @return whether the cell at the given point is free space - */ - virtual bool IsFree(const Vector2 &rPose) const { - uint8_t *pOffsets = reinterpret_cast(GetDataPointer(rPose)); - if (*pOffsets == GridStates_Free) { - return true; - } - - return false; - } - - /** - * Casts a ray from the given point (up to the given max range) - * and returns the distance to the closest obstacle - * @param rPose2 - * @param maxRange - * @return distance to closest obstacle - */ - virtual double RayCast(const Pose2 &rPose2, double maxRange) const { - double scale = GetCoordinateConverter()->GetScale(); - - double x = rPose2.GetX(); - double y = rPose2.GetY(); - double theta = rPose2.GetHeading(); - - double sinTheta = sin(theta); - double cosTheta = cos(theta); - - double xStop = x + maxRange * cosTheta; - double xSteps = 1 + fabs(xStop - x) * scale; - - double yStop = y + maxRange * sinTheta; - double ySteps = 1 + fabs(yStop - y) * scale; - - double steps = amath::Maximum(xSteps, ySteps); - double delta = maxRange / steps; - double distance = delta; - - for (uint32_t i = 1; i < steps; i++) { - double x1 = x + distance * cosTheta; - double y1 = y + distance * sinTheta; - - Vector2 gridIndex = WorldToGrid(Vector2(x1, y1)); - if (IsValidGridIndex(gridIndex) && IsFree(gridIndex)) { - distance = (i + 1) * delta; - } else { - break; - } - } - - return (distance < maxRange) ? distance : maxRange; - } - - /** - * Sets the minimum number of beams that must pass through a cell before it - * will be considered to be occupied or unoccupied. - * This prevents stray beams from messing up the map. - */ - void SetMinPassThrough(uint32_t count) { - m_pMinPassThrough = count; - } - - /** - * Sets the minimum ratio of beams hitting cell to beams passing through - * cell for cell to be marked as occupied. - */ - void SetOccupancyThreshold(double thresh) { - m_pOccupancyThreshold = thresh; - } - -protected: - /** - * Get cell hit grid - * @return Grid* - */ - virtual Grid *GetCellHitsCounts() { return m_pCellHitsCnt; } - - /** - * Get cell pass grid - * @return Grid* - */ - virtual Grid *GetCellPassCounts() { return m_pCellPassCnt; } - -protected: - /** - * Calculate grid dimensions from localized range scans - * @param rScans - * @param resolution - * @param rWidth - * @param rHeight - * @param rOffset - */ - static void ComputeDimensions(const LocalizedRangeScanVector &rScans, - double resolution, int32_t &rWidth, - int32_t &rHeight, - Vector2 &rOffset) { - BoundingBox2 boundingBox; - for (auto iter : rScans) { - boundingBox.Add(iter->GetBoundingBox()); - } - - double scale = 1.0 / resolution; - Size2 size = boundingBox.GetSize(); - - rWidth = static_cast(amath::Round(size.GetWidth() * scale)); - rHeight = static_cast(amath::Round(size.GetHeight() * scale)); - rOffset = boundingBox.GetMinimum(); - } - - /** - * Create grid using scans - * @param rScans - */ - virtual void CreateFromScans(const LocalizedRangeScanVector &rScans) { - m_pCellPassCnt->Resize(GetWidth(), GetHeight()); - m_pCellPassCnt->GetCoordinateConverter()->SetOffset( - GetCoordinateConverter()->GetOffset()); - - m_pCellHitsCnt->Resize(GetWidth(), GetHeight()); - m_pCellHitsCnt->GetCoordinateConverter()->SetOffset( - GetCoordinateConverter()->GetOffset()); - - for (auto iter : rScans) { - LocalizedRangeScan *pScan = iter; - AddScan(pScan); - } - - Update(); - } - - /** - * Adds the scan's information to this grid's counters (optionally - * update the grid's cells' occupancy status) - * @param pScan - * @param doUpdate whether to update the grid's cell's occupancy status - * @return returns false if an endpoint fell off the grid, otherwise true - */ - virtual bool AddScan(LocalizedRangeScan *pScan, bool doUpdate = false) { - double _rangeThreshold = (rangeThreshold > pScan->GetMinimumRange() && - rangeThreshold < pScan->GetMaximumRange()) - ? rangeThreshold - : pScan->GetRangeThreshold(); - double maxRange = pScan->GetMaximumRange(); - double minRange = pScan->GetMinimumRange(); - - Vector2 scanPosition = pScan->GetCorrectedPose().GetPosition(); - - // get scan point readings - const PointVectorDouble &rPointReadings = pScan->GetPointReadings(false); - - bool isAllInMap = true; - - // draw lines from scan position to all point readings - int pointIndex = 0; - for (auto pointsIter : rPointReadings) { - Vector2 point = pointsIter; - double rangeReading = pScan->GetRangeReadings()[pointIndex]; - bool isEndPointValid = rangeReading < (_rangeThreshold - KT_TOLERANCE); - - if (rangeReading <= minRange || rangeReading >= maxRange || - std::isnan(rangeReading)) { - // ignore these readings - pointIndex++; - continue; - } else if (rangeReading >= _rangeThreshold) { - // trace up to range reading - double ratio = _rangeThreshold / rangeReading; - double dx = point.GetX() - scanPosition.GetX(); - double dy = point.GetY() - scanPosition.GetY(); - point.SetX(scanPosition.GetX() + ratio * dx); - point.SetY(scanPosition.GetY() + ratio * dy); - } - - bool isInMap = - RayTrace(scanPosition, point, isEndPointValid, doUpdate); - if (!isInMap) { - isAllInMap = false; - } - - pointIndex++; - } - - return isAllInMap; - } - - /** - * Traces a beam from the start position to the end position marking - * the bookkeeping arrays accordingly. - * @param rWorldFrom start position of beam - * @param rWorldTo end position of beam - * @param isEndPointValid is the reading within the range threshold? - * @param doUpdate whether to update the cells' occupancy status immediately - * @return returns false if an endpoint fell off the grid, otherwise true - */ - virtual bool RayTrace(const Vector2 &rWorldFrom, - const Vector2 &rWorldTo, - bool isEndPointValid, bool doUpdate = false) { - assert(m_pCellPassCnt != NULL && m_pCellHitsCnt != NULL); - - Vector2 gridFrom = m_pCellPassCnt->WorldToGrid(rWorldFrom); - Vector2 gridTo = m_pCellPassCnt->WorldToGrid(rWorldTo); - - CellUpdater *pCellUpdater = doUpdate ? m_pCellUpdater : NULL; - m_pCellPassCnt->TraceLine(gridFrom.GetX(), gridFrom.GetY(), gridTo.GetX(), - gridTo.GetY(), pCellUpdater); - - // for the end point - if (isEndPointValid) { - if (m_pCellPassCnt->IsValidGridIndex(gridTo)) { - int32_t index = m_pCellPassCnt->GridIndex(gridTo, false); - - uint32_t *pCellPassCntPtr = m_pCellPassCnt->GetDataPointer(); - uint32_t *pCellHitCntPtr = m_pCellHitsCnt->GetDataPointer(); - - // increment cell pass through and hit count - pCellPassCntPtr[index]++; - pCellHitCntPtr[index]++; - - if (doUpdate) { - (*m_pCellUpdater)(index); - } - } - } - - return m_pCellPassCnt->IsValidGridIndex(gridTo); - } - - /** - * Updates a single cell's value based on the given counters - * @param pCell - * @param cellPassCnt - * @param cellHitCnt - */ - virtual void UpdateCell(uint8_t *pCell, uint32_t cellPassCnt, - uint32_t cellHitCnt) { - if (cellPassCnt > m_pMinPassThrough) { - double hitRatio = static_cast(cellHitCnt) / - static_cast(cellPassCnt); - - if (hitRatio > m_pOccupancyThreshold) { - *pCell = GridStates_Occupied; - } else { - *pCell = GridStates_Free; - } - } - } - - /** - * Update the grid based on the values in m_pCellHitsCnt and m_pCellPassCnt - */ - virtual void Update() { - assert(m_pCellPassCnt != NULL && m_pCellHitsCnt != NULL); - - // clear grid - Clear(); - - // set occupancy status of cells - uint8_t *pDataPtr = GetDataPointer(); - uint32_t *pCellPassCntPtr = m_pCellPassCnt->GetDataPointer(); - uint32_t *pCellHitCntPtr = m_pCellHitsCnt->GetDataPointer(); - - uint32_t nBytes = GetDataSize(); - for (uint32_t i = 0; i < nBytes; - i++, pDataPtr++, pCellPassCntPtr++, pCellHitCntPtr++) { - UpdateCell(pDataPtr, *pCellPassCntPtr, *pCellHitCntPtr); - } - } - - /** - * Resizes the grid (deletes all old data) - * @param width - * @param height - */ - virtual void Resize(int32_t width, int32_t height) { - Grid::Resize(width, height); - m_pCellPassCnt->Resize(width, height); - m_pCellHitsCnt->Resize(width, height); - } - -protected: - /** - * Counters of number of times a beam passed through a cell - */ - Grid *m_pCellPassCnt; - - /** - * Counters of number of times a beam ended at a cell - */ - Grid *m_pCellHitsCnt; - -private: - /** - * Restrict the copy constructor - */ - OccupancyGrid(const OccupancyGrid &); - - /** - * Restrict the assignment operator - */ - const OccupancyGrid &operator=(const OccupancyGrid &); - -private: - CellUpdater *m_pCellUpdater; - - //////////////////////////////////////////////////////////// - // NOTE: These two values are dependent on the resolution. If the resolution - // is too small, then not many beams will hit the cell! - - // Number of beams that must pass through a cell before it will be considered - // to be occupied or unoccupied. This prevents stray beams from messing up - // the map. - uint32_t m_pMinPassThrough; - - // Minimum ratio of beams hitting cell to beams passing through cell for cell - // to be marked as occupied - double m_pOccupancyThreshold; - double rangeThreshold; -}; // OccupancyGrid - -#endif diff --git a/include/Pose.h b/include/Pose.h deleted file mode 100644 index c252fe2..0000000 --- a/include/Pose.h +++ /dev/null @@ -1,332 +0,0 @@ -#ifndef POSE_H -#define POSE_H - -#include - -#include "Vector2.h" -#include "Vector3.h" -#include "Quaternion.h" - -class Pose3; - -class Pose2 { -public: - /** - * Default Constructor - */ - Pose2() : m_Heading(0.0) {} - - /** - * Constructor initializing pose parameters - * @param rPosition position - * @param heading heading - **/ - Pose2(const Vector2 &rPosition, double heading) - : m_Position(rPosition), m_Heading(heading) {} - - /** - * Constructor initializing pose parameters - * @param x x-coordinate - * @param y y-coordinate - * @param heading heading - **/ - Pose2(double x, double y, double heading) - : m_Position(x, y), m_Heading(heading) {} - - /** - * Constructs a Pose2 object from a Pose3. - */ - Pose2(const Pose3 &rPose); - - /** - * Copy constructor - */ - Pose2(const Pose2 &rOther) - : m_Position(rOther.m_Position), m_Heading(rOther.m_Heading) {} - -public: - /** - * Returns the x-coordinate - * @return the x-coordinate of the pose - */ - inline double GetX() const { return m_Position.GetX(); } - - /** - * Sets the x-coordinate - * @param x the x-coordinate of the pose - */ - inline void SetX(double x) { m_Position.SetX(x); } - - /** - * Returns the y-coordinate - * @return the y-coordinate of the pose - */ - inline double GetY() const { return m_Position.GetY(); } - - /** - * Sets the y-coordinate - * @param y the y-coordinate of the pose - */ - inline void SetY(double y) { m_Position.SetY(y); } - - /** - * Returns the position - * @return the position of the pose - */ - inline const Vector2 &GetPosition() const { return m_Position; } - - /** - * Sets the position - * @param rPosition of the pose - */ - inline void SetPosition(const Vector2 &rPosition) { - m_Position = rPosition; - } - - /** - * Returns the heading of the pose (in radians) - * @return the heading of the pose - */ - inline double GetHeading() const { return m_Heading; } - - /** - * Sets the heading - * @param heading of the pose - */ - inline void SetHeading(double heading) { m_Heading = heading; } - - /** - * Return the squared distance between two Pose2 - * @return squared distance - */ - inline double SquaredDistance(const Pose2 &rOther) const { - return m_Position.SquaredDistance(rOther.m_Position); - } - -public: - /** - * Assignment operator - */ - inline Pose2 &operator=(const Pose2 &rOther) { - m_Position = rOther.m_Position; - m_Heading = rOther.m_Heading; - - return *this; - } - - /** - * Equality operator - */ - inline bool operator==(const Pose2 &rOther) const { - return (m_Position == rOther.m_Position && m_Heading == rOther.m_Heading); - } - - /** - * Inequality operator - */ - inline bool operator!=(const Pose2 &rOther) const { - return (m_Position != rOther.m_Position || m_Heading != rOther.m_Heading); - } - - /** - * In place Pose2 add. - */ - inline void operator+=(const Pose2 &rOther) { - m_Position += rOther.m_Position; - m_Heading = amath::NormalizeAngle(m_Heading + rOther.m_Heading); - } - - /** - * Binary Pose2 add - * @param rOther - * @return Pose2 sum - */ - inline Pose2 operator+(const Pose2 &rOther) const { - return Pose2(m_Position + rOther.m_Position, - amath::NormalizeAngle(m_Heading + rOther.m_Heading)); - } - - /** - * Binary Pose2 subtract - * @param rOther - * @return Pose2 difference - */ - inline Pose2 operator-(const Pose2 &rOther) const { - return Pose2(m_Position - rOther.m_Position, - amath::NormalizeAngle(m_Heading - rOther.m_Heading)); - } - - /** - * Read pose from input stream - * @param rStream input stream - */ - friend inline std::istream &operator>>(std::istream &rStream, - const Pose2 & /*rPose*/) { - // Implement me!! - return rStream; - } - - /** - * Write this pose onto output stream - * @param rStream output stream - * @param rPose to read - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Pose2 &rPose) { - rStream << rPose.m_Position.GetX() << " " << rPose.m_Position.GetY() << " " - << rPose.m_Heading; - return rStream; - } - -private: - Vector2 m_Position; - - double m_Heading; -}; // Pose2 - -/** - * Type declaration of Pose2 vector - */ -typedef std::vector Pose2Vector; - -/** - * Defines a position and orientation in 3-dimensional space. - * Karto uses a right-handed coordinate system with X, Y as the 2-D ground plane - * and X is forward and Y is left. Values in Vector3 used to define position - * must have units of meters. The value of angle when defining orientation in - * two dimensions must be in units of radians. The definition of orientation in - * three dimensions uses quaternions. - */ -class Pose3 { -public: - /** - * Default constructor - */ - Pose3() {} - - /** - * Create a new Pose3 object from the given position. - * @param rPosition position vector in three space. - */ - Pose3(const Vector3 &rPosition) : m_Position(rPosition) {} - - /** - * Create a new Pose3 object from the given position and orientation. - * @param rPosition position vector in three space. - * @param rOrientation quaternion orientation in three space. - */ - Pose3(const Vector3 &rPosition, const Quaternion &rOrientation) - : m_Position(rPosition), m_Orientation(rOrientation) {} - - /** - * Copy constructor - */ - Pose3(const Pose3 &rOther) - : m_Position(rOther.m_Position), m_Orientation(rOther.m_Orientation) {} - - /** - * Constructs a Pose3 object from a Pose2. - */ - Pose3(const Pose2 &rPose) { - m_Position = Vector3(rPose.GetX(), rPose.GetY(), 0.0); - m_Orientation.FromEulerAngles(rPose.GetHeading(), 0.0, 0.0); - } - -public: - /** - * Get the position of the pose as a 3D vector as const. Values have units of - * meters. - * @return 3-dimensional position vector as const - */ - inline const Vector3 &GetPosition() const { return m_Position; } - - /** - * Set the position of the pose as a 3D vector. Values have units of meters. - * @return 3-dimensional position vector - */ - inline void SetPosition(const Vector3 &rPosition) { - m_Position = rPosition; - } - - /** - * Get the orientation quaternion of the pose as const. - * @return orientation quaternion as const - */ - inline const Quaternion &GetOrientation() const { return m_Orientation; } - - /** - * Get the orientation quaternion of the pose. - * @return orientation quaternion - */ - inline void SetOrientation(const Quaternion &rOrientation) { - m_Orientation = rOrientation; - } - - /** - * Returns a string representation of this pose - * @return string representation of this pose - */ - inline std::string ToString() { - // std::stringstream converter; - // converter.precision(std::numeric_limits::digits10); - - // converter << GetPosition() << " " << GetOrientation(); - - // return converter.str(); - return "Notimplemented"; - } - -public: - /** - * Assignment operator - */ - inline Pose3 &operator=(const Pose3 &rOther) { - m_Position = rOther.m_Position; - m_Orientation = rOther.m_Orientation; - - return *this; - } - - /** - * Equality operator - */ - inline bool operator==(const Pose3 &rOther) const { - return (m_Position == rOther.m_Position && - m_Orientation == rOther.m_Orientation); - } - - /** - * Inequality operator - */ - inline bool operator!=(const Pose3 &rOther) const { - return (m_Position != rOther.m_Position || - m_Orientation != rOther.m_Orientation); - } - - /** - * Write Pose3 onto output stream - * @param rStream output stream - * @param rPose to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Pose3 &rPose) { - rStream << rPose.GetPosition() << ", " << rPose.GetOrientation(); - return rStream; - } - - /** - * Read Pose3 from input stream - * @param rStream input stream - */ - friend inline std::istream &operator>>(std::istream &rStream, - const Pose3 & /*rPose*/) { - // Implement me!! - return rStream; - } - -private: - Vector3 m_Position; - Quaternion m_Orientation; -}; // Pose3 - -#endif diff --git a/include/Quaternion.h b/include/Quaternion.h deleted file mode 100644 index c49370e..0000000 --- a/include/Quaternion.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef QUATERNION_H -#define QUATERNION_H - -#include -#include - -#include "AdditionalMath.h" - -class Quaternion { -public: - /** - * Create a quaternion with default (x=0, y=0, z=0, w=1) values - */ - inline Quaternion() { - m_Values[0] = 0.0; - m_Values[1] = 0.0; - m_Values[2] = 0.0; - m_Values[3] = 1.0; - } - - /** - * Create a quaternion using x, y, z, w values. - * @param x - * @param y - * @param z - * @param w - */ - inline Quaternion(double x, double y, double z, double w) { - m_Values[0] = x; - m_Values[1] = y; - m_Values[2] = z; - m_Values[3] = w; - } - - /** - * Copy constructor - */ - inline Quaternion(const Quaternion &rQuaternion) { - m_Values[0] = rQuaternion.m_Values[0]; - m_Values[1] = rQuaternion.m_Values[1]; - m_Values[2] = rQuaternion.m_Values[2]; - m_Values[3] = rQuaternion.m_Values[3]; - } - -public: - /** - * Returns the X-value - * @return Return the X-value of the quaternion - */ - inline double GetX() const { return m_Values[0]; } - - /** - * Sets the X-value - * @param x X-value of the quaternion - */ - inline void SetX(double x) { m_Values[0] = x; } - - /** - * Returns the Y-value - * @return Return the Y-value of the quaternion - */ - inline double GetY() const { return m_Values[1]; } - - /** - * Sets the Y-value - * @param y Y-value of the quaternion - */ - inline void SetY(double y) { m_Values[1] = y; } - - /** - * Returns the Z-value - * @return Return the Z-value of the quaternion - */ - inline double GetZ() const { return m_Values[2]; } - - /** - * Sets the Z-value - * @param z Z-value of the quaternion - */ - inline void SetZ(double z) { m_Values[2] = z; } - - /** - * Returns the W-value - * @return Return the W-value of the quaternion - */ - inline double GetW() const { return m_Values[3]; } - - /** - * Sets the W-value - * @param w W-value of the quaternion - */ - inline void SetW(double w) { m_Values[3] = w; } - - /** - * Converts this quaternion into Euler angles - * Source: - * http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm - * @param rYaw - * @param rPitch - * @param rRoll - */ - void ToEulerAngles(double &rYaw, double &rPitch, double &rRoll) const { - double test = m_Values[0] * m_Values[1] + m_Values[2] * m_Values[3]; - - if (test > 0.499) { - // singularity at north pole - rYaw = 2 * atan2(m_Values[0], m_Values[3]); - ; - rPitch = KT_PI_2; - rRoll = 0; - } else if (test < -0.499) { - // singularity at south pole - rYaw = -2 * atan2(m_Values[0], m_Values[3]); - rPitch = -KT_PI_2; - rRoll = 0; - } else { - double sqx = m_Values[0] * m_Values[0]; - double sqy = m_Values[1] * m_Values[1]; - double sqz = m_Values[2] * m_Values[2]; - - rYaw = - atan2(2 * m_Values[1] * m_Values[3] - 2 * m_Values[0] * m_Values[2], - 1 - 2 * sqy - 2 * sqz); - rPitch = asin(2 * test); - rRoll = - atan2(2 * m_Values[0] * m_Values[3] - 2 * m_Values[1] * m_Values[2], - 1 - 2 * sqx - 2 * sqz); - } - } - - /** - * Set x,y,z,w values of the quaternion based on Euler angles. - * Source: - * http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm - * @param yaw - * @param pitch - * @param roll - */ - void FromEulerAngles(double yaw, double pitch, double roll) { - double angle; - - angle = yaw * 0.5; - double cYaw = cos(angle); - double sYaw = sin(angle); - - angle = pitch * 0.5; - double cPitch = cos(angle); - double sPitch = sin(angle); - - angle = roll * 0.5; - double cRoll = cos(angle); - double sRoll = sin(angle); - - m_Values[0] = sYaw * sPitch * cRoll + cYaw * cPitch * sRoll; - m_Values[1] = sYaw * cPitch * cRoll + cYaw * sPitch * sRoll; - m_Values[2] = cYaw * sPitch * cRoll - sYaw * cPitch * sRoll; - m_Values[3] = cYaw * cPitch * cRoll - sYaw * sPitch * sRoll; - } - - /** - * Assignment operator - * @param rQuaternion - */ - inline Quaternion &operator=(const Quaternion &rQuaternion) { - m_Values[0] = rQuaternion.m_Values[0]; - m_Values[1] = rQuaternion.m_Values[1]; - m_Values[2] = rQuaternion.m_Values[2]; - m_Values[3] = rQuaternion.m_Values[3]; - - return (*this); - } - - /** - * Equality operator returns true if the corresponding x, y, z, w values of - * each quaternion are the same values. - * @param rOther - */ - inline bool operator==(const Quaternion &rOther) const { - return (m_Values[0] == rOther.m_Values[0] && - m_Values[1] == rOther.m_Values[1] && - m_Values[2] == rOther.m_Values[2] && - m_Values[3] == rOther.m_Values[3]); - } - - /** - * Inequality operator returns true if any of the corresponding x, y, z, w - * values of each quaternion not the same. - * @param rOther - */ - inline bool operator!=(const Quaternion &rOther) const { - return (m_Values[0] != rOther.m_Values[0] || - m_Values[1] != rOther.m_Values[1] || - m_Values[2] != rOther.m_Values[2] || - m_Values[3] != rOther.m_Values[3]); - } - - /** - * Write this quaternion onto output stream - * @param rStream output stream - * @param rQuaternion - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Quaternion &rQuaternion) { - rStream << rQuaternion.m_Values[0] << " " << rQuaternion.m_Values[1] << " " - << rQuaternion.m_Values[2] << " " << rQuaternion.m_Values[3]; - return rStream; - } - -private: - double m_Values[4]; -}; - -#endif diff --git a/include/Rectangle2.h b/include/Rectangle2.h deleted file mode 100644 index 292660b..0000000 --- a/include/Rectangle2.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef RECT2_H -#define RECT2_H -#include "Vector2.h" -#include "Size2.h" - -template class Rectangle2 { -public: - /** - * Default constructor - */ - Rectangle2() {} - - /** - * Constructor initializing rectangle parameters - * @param x x-coordinate of left edge of rectangle - * @param y y-coordinate of bottom edge of rectangle - * @param width width of rectangle - * @param height height of rectangle - */ - Rectangle2(T x, T y, T width, T height) - : m_Position(x, y), m_Size(width, height) {} - - /** - * Constructor initializing rectangle parameters - * @param rPosition (x,y)-coordinate of rectangle - * @param rSize Size of the rectangle - */ - Rectangle2(const Vector2 &rPosition, const Size2 &rSize) - : m_Position(rPosition), m_Size(rSize) {} - - /** - * Copy constructor - */ - Rectangle2(const Rectangle2 &rOther) - : m_Position(rOther.m_Position), m_Size(rOther.m_Size) {} - -public: - /** - * Gets the x-coordinate of the left edge of this rectangle - * @return the x-coordinate of the left edge of this rectangle - */ - inline T GetX() const { return m_Position.GetX(); } - - /** - * Sets the x-coordinate of the left edge of this rectangle - * @param x the x-coordinate of the left edge of this rectangle - */ - inline void SetX(T x) { m_Position.SetX(x); } - - /** - * Gets the y-coordinate of the bottom edge of this rectangle - * @return the y-coordinate of the bottom edge of this rectangle - */ - inline T GetY() const { return m_Position.GetY(); } - - /** - * Sets the y-coordinate of the bottom edge of this rectangle - * @param y the y-coordinate of the bottom edge of this rectangle - */ - inline void SetY(T y) { m_Position.SetY(y); } - - /** - * Gets the width of this rectangle - * @return the width of this rectangle - */ - inline T GetWidth() const { return m_Size.GetWidth(); } - - /** - * Sets the width of this rectangle - * @param width the width of this rectangle - */ - inline void SetWidth(T width) { m_Size.SetWidth(width); } - - /** - * Gets the height of this rectangle - * @return the height of this rectangle - */ - inline T GetHeight() const { return m_Size.GetHeight(); } - - /** - * Sets the height of this rectangle - * @param height the height of this rectangle - */ - inline void SetHeight(T height) { m_Size.SetHeight(height); } - - /** - * Gets the position of this rectangle - * @return the position of this rectangle - */ - inline const Vector2 &GetPosition() const { return m_Position; } - - /** - * Sets the position of this rectangle - * @param rX x - * @param rY y - */ - inline void SetPosition(const T &rX, const T &rY) { - m_Position = Vector2(rX, rY); - } - - /** - * Sets the position of this rectangle - * @param rPosition position - */ - inline void SetPosition(const Vector2 &rPosition) { - m_Position = rPosition; - } - - /** - * Gets the size of this rectangle - * @return the size of this rectangle - */ - inline const Size2 &GetSize() const { return m_Size; } - - /** - * Sets the size of this rectangle - * @param rSize size - */ - inline void SetSize(const Size2 &rSize) { m_Size = rSize; } - - /** - * Gets the center of this rectangle - * @return the center of this rectangle - */ - inline const Vector2 GetCenter() const { - return Vector2(m_Position.GetX() + m_Size.GetWidth() * 0.5, - m_Position.GetY() + m_Size.GetHeight() * 0.5); - } - -public: - /** - * Assignment operator - */ - Rectangle2 &operator=(const Rectangle2 &rOther) { - m_Position = rOther.m_Position; - m_Size = rOther.m_Size; - - return *this; - } - - /** - * Equality operator - */ - inline bool operator==(const Rectangle2 &rOther) const { - return (m_Position == rOther.m_Position && m_Size == rOther.m_Size); - } - - /** - * Inequality operator - */ - inline bool operator!=(const Rectangle2 &rOther) const { - return (m_Position != rOther.m_Position || m_Size != rOther.m_Size); - } - -private: - Vector2 m_Position; - Size2 m_Size; -}; // Rectangle2 - -#endif diff --git a/include/ScanMatcher.h b/include/ScanMatcher.h deleted file mode 100644 index 125fdd4..0000000 --- a/include/ScanMatcher.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef SCAN_MATCH_H -#define SCAN_MATCH_H - -#include "Grid.h" -#include "Pose.h" -#include "Matrix.h" -#include "CorrelationGrid.h" -#include "LocalizedRangeScan.h" -#include "GridIndexLookup.h" -#include - -#define MAX_VARIANCE 500.0 -#define DISTANCE_PENALTY_GAIN 0.2 -#define ANGLE_PENALTY_GAIN 0.2 - - -class ScanMatcherConfig -{ -public: - /** - * Destructor - */ - // virtual ~ScanMatcherConfig(); - - ScanMatcherConfig( - // Mapper* pMapper - ) - : - m_pCoarseAngleResolution(0.03490658503988659), - m_pCoarseSearchAngleOffset(0.3490658503988659), - m_pFineSearchAngleResolution(0.003490658503988659), - m_pDistanceVariancePenalty(0.5), - m_pAngleVariancePenalty(0.3490658503988659), - m_pMinimumDistancePenalty(1.0), - m_pMinimumAnglePenalty(0.9), - m_pUseResponseExpansion(true), - searchSize(0.3), - resolution(0.01), - smearDeviation(0.03), - rangeThreshold(40) - { - } - - double m_pCoarseAngleResolution; - double m_pCoarseSearchAngleOffset; - double m_pFineSearchAngleResolution; - double m_pDistanceVariancePenalty; - double m_pAngleVariancePenalty; - double m_pMinimumDistancePenalty; - double m_pMinimumAnglePenalty; - bool m_pUseResponseExpansion; - double searchSize; - double resolution; - double smearDeviation; - double rangeThreshold; -}; - -class ScanMatcher -{ -public: - /** - * Destructor - */ - virtual ~ScanMatcher(); - -public: - /** - * Create a scan matcher with the given parameters - */ - static ScanMatcher* Create(std::shared_ptr config); - - /** - * Match given scan against set of scans - * @param pScan scan being scan-matched - * @param rBaseScans set of scans whose points will mark cells in grid as being occupied - * @param rMean output parameter of mean (best pose) of match - * @param rCovariance output parameter of covariance of match - * @param doPenalize whether to penalize matches further from the search center - * @param doRefineMatch whether to do finer-grained matching if coarse match is good (default is true) - * @return strength of response - */ - double MatchScan(LocalizedRangeScan* pScan, - const LocalizedRangeScanVector& rBaseScans, - Pose2& rMean, Matrix3& rCovariance, - bool doPenalize = true, - bool doRefineMatch = true); - - /** - * Finds the best pose for the scan centering the search in the correlation grid - * at the given pose and search in the space by the vector and angular offsets - * in increments of the given resolutions - * @param pScan scan to match against correlation grid - * @param rSearchCenter the center of the search space - * @param rSearchSpaceOffset searches poses in the area offset by this vector around search center - * @param rSearchSpaceResolution how fine a granularity to search in the search space - * @param searchAngleOffset searches poses in the angles offset by this angle around search center - * @param searchAngleResolution how fine a granularity to search in the angular search space - * @param doPenalize whether to penalize matches further from the search center - * @param rMean output parameter of mean (best pose) of match - * @param rCovariance output parameter of covariance of match - * @param doingFineMatch whether to do a finer search after coarse search - * @return strength of response - */ - double CorrelateScan(LocalizedRangeScan* pScan, - const Pose2& rSearchCenter, - const Vector2& rSearchSpaceOffset, - const Vector2& rSearchSpaceResolution, - double searchAngleOffset, - double searchAngleResolution, - bool doPenalize, - Pose2& rMean, - Matrix3& rCovariance, - bool doingFineMatch); - - /** - * Computes the positional covariance of the best pose - * @param rBestPose - * @param bestResponse - * @param rSearchCenter - * @param rSearchSpaceOffset - * @param rSearchSpaceResolution - * @param searchAngleResolution - * @param rCovariance - */ - void ComputePositionalCovariance(const Pose2& rBestPose, - double bestResponse, - const Pose2& rSearchCenter, - const Vector2& rSearchSpaceOffset, - const Vector2& rSearchSpaceResolution, - double searchAngleResolution, - Matrix3& rCovariance); - - /** - * Computes the angular covariance of the best pose - * @param rBestPose - * @param bestResponse - * @param rSearchCenter - * @param searchAngleOffset - * @param searchAngleResolution - * @param rCovariance - */ - void ComputeAngularCovariance(const Pose2& rBestPose, - double bestResponse, - const Pose2& rSearchCenter, - double searchAngleOffset, - double searchAngleResolution, - Matrix3& rCovariance); - - /** - * Gets the correlation grid data (for debugging) - * @return correlation grid - */ - inline CorrelationGrid* GetCorrelationGrid() const - { - return m_pCorrelationGrid; - } - -private: - /** - * Marks cells where scans' points hit as being occupied - * @param rScans scans whose points will mark cells in grid as being occupied - * @param viewPoint do not add points that belong to scans "opposite" the view point - */ - void AddScans(const LocalizedRangeScanVector& rScans, Vector2 viewPoint); - - /** - * Marks cells where scans' points hit as being occupied. Can smear points as they are added. - * @param pScan scan whose points will mark cells in grid as being occupied - * @param viewPoint do not add points that belong to scans "opposite" the view point - * @param doSmear whether the points will be smeared - */ - void AddScan(LocalizedRangeScan* pScan, const Vector2& rViewPoint, bool doSmear = true); - - /** - * Compute which points in a scan are on the same side as the given viewpoint - * @param pScan - * @param rViewPoint - * @return points on the same side - */ - PointVectorDouble FindValidPoints(LocalizedRangeScan* pScan, const Vector2& rViewPoint) const; - - /** - * Get response at given position for given rotation (only look up valid points) - * @param angleIndex - * @param gridPositionIndex - * @return response - */ - double GetResponse(int32_t angleIndex, int32_t gridPositionIndex) const; - -protected: - /** - * Default constructor - */ - ScanMatcher(std::shared_ptr config_) - : - config(config_), - m_pCorrelationGrid(NULL) - , m_pSearchSpaceProbs(NULL) - , m_pGridLookup(NULL) - { - } - -private: - std::shared_ptr config; - CorrelationGrid* m_pCorrelationGrid; - Grid* m_pSearchSpaceProbs; - - GridIndexLookup* m_pGridLookup; -}; // ScanMatcher - -#endif diff --git a/include/SensorData.h b/include/SensorData.h deleted file mode 100644 index 8b06609..0000000 --- a/include/SensorData.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef SENSOR_DATA_H -#define SENSOR_DATA_H - -#include "CustomData.h" -#include "Object.h" - -class SensorData : public Object { -public: - /** - * Destructor - */ - virtual ~SensorData(); - -public: - /** - * Gets sensor data id - * @return sensor id - */ - inline int32_t GetStateId() const { return m_StateId; } - - /** - * Sets sensor data id - * @param stateId id - */ - inline void SetStateId(int32_t stateId) { m_StateId = stateId; } - - /** - * Gets sensor unique id - * @return unique id - */ - inline int32_t GetUniqueId() const { return m_UniqueId; } - - /** - * Sets sensor unique id - * @param uniqueId - */ - inline void SetUniqueId(uint32_t uniqueId) { m_UniqueId = uniqueId; } - - /** - * Gets sensor data time - * @return time - */ - inline double GetTime() const { return m_Time; } - - /** - * Sets sensor data time - * @param time - */ - inline void SetTime(double time) { m_Time = time; } - - /** - * Get the sensor that created this sensor data - * @return sensor - */ - inline const Name &GetSensorName() const { return m_SensorName; } - - /** - * Add a CustomData object to sensor data - * @param pCustomData - */ - inline void AddCustomData(CustomData *pCustomData) { - m_CustomData.push_back(pCustomData); - } - - /** - * Get all custom data objects assigned to sensor data - * @return CustomDataVector& - */ - inline const CustomDataVector &GetCustomData() const { return m_CustomData; } - -protected: - /** - * Construct a SensorData object with a sensor name - */ - SensorData(const Name &rSensorName); - -private: - /** - * Restrict the copy constructor - */ - SensorData(const SensorData &); - - /** - * Restrict the assignment operator - */ - const SensorData &operator=(const SensorData &); - -private: - /** - * ID unique to individual sensor - */ - int32_t m_StateId; - - /** - * ID unique across all sensor data - */ - int32_t m_UniqueId; - - /** - * Sensor that created this sensor data - */ - Name m_SensorName; - - /** - * Time the sensor data was created - */ - double m_Time; - - CustomDataVector m_CustomData; -}; - -#endif diff --git a/include/Size2.h b/include/Size2.h deleted file mode 100644 index d1d6356..0000000 --- a/include/Size2.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef SIZE2_H -#define SIZE2_H - -#include - -template class Size2 { -public: - /** - * Default constructor - */ - Size2() : m_Width(0), m_Height(0) {} - - /** - * Constructor initializing point location - * @param width - * @param height - */ - Size2(T width, T height) : m_Width(width), m_Height(height) {} - - /** - * Copy constructor - * @param rOther - */ - Size2(const Size2 &rOther) - : m_Width(rOther.m_Width), m_Height(rOther.m_Height) {} - -public: - /** - * Gets the width - * @return the width - */ - inline const T GetWidth() const { return m_Width; } - - /** - * Sets the width - * @param width - */ - inline void SetWidth(T width) { m_Width = width; } - - /** - * Gets the height - * @return the height - */ - inline const T GetHeight() const { return m_Height; } - - /** - * Sets the height - * @param height - */ - inline void SetHeight(T height) { m_Height = height; } - - /** - * Assignment operator - */ - inline Size2 &operator=(const Size2 &rOther) { - m_Width = rOther.m_Width; - m_Height = rOther.m_Height; - - return (*this); - } - - /** - * Equality operator - */ - inline bool operator==(const Size2 &rOther) const { - return (m_Width == rOther.m_Width && m_Height == rOther.m_Height); - } - - /** - * Inequality operator - */ - inline bool operator!=(const Size2 &rOther) const { - return (m_Width != rOther.m_Width || m_Height != rOther.m_Height); - } - - /** - * Write Size2 onto output stream - * @param rStream output stream - * @param rSize to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Size2 &rSize) { - rStream << "(" << rSize.m_Width << ", " << rSize.m_Height << ")"; - return rStream; - } - -private: - T m_Width; - T m_Height; -}; // Size2 - -#endif diff --git a/include/Transform.h b/include/Transform.h deleted file mode 100644 index 6349b92..0000000 --- a/include/Transform.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef TRANSFORM_H -#define TRANSFORM_H -#include "Pose.h" -#include "Matrix.h" -/** - * Implementation of a Pose2 transform - */ -class Transform { -public: - /** - * Constructs a transformation from the origin to the given pose - * @param rPose pose - */ - Transform(const Pose2 &rPose) { SetTransform(Pose2(), rPose); } - - /** - * Constructs a transformation from the first pose to the second pose - * @param rPose1 first pose - * @param rPose2 second pose - */ - Transform(const Pose2 &rPose1, const Pose2 &rPose2) { - SetTransform(rPose1, rPose2); - } - -public: - /** - * Transforms the pose according to this transform - * @param rSourcePose pose to transform from - * @return transformed pose - */ - inline Pose2 TransformPose(const Pose2 &rSourcePose) { - Pose2 newPosition = m_Transform + m_Rotation * rSourcePose; - double angle = amath::NormalizeAngle(rSourcePose.GetHeading() + - m_Transform.GetHeading()); - - return Pose2(newPosition.GetPosition(), angle); - } - - /** - * Inverse transformation of the pose according to this transform - * @param rSourcePose pose to transform from - * @return transformed pose - */ - inline Pose2 InverseTransformPose(const Pose2 &rSourcePose) { - Pose2 newPosition = m_InverseRotation * (rSourcePose - m_Transform); - double angle = amath::NormalizeAngle(rSourcePose.GetHeading() - - m_Transform.GetHeading()); - - // components of transform - return Pose2(newPosition.GetPosition(), angle); - } - -private: - /** - * Sets this to be the transformation from the first pose to the second pose - * @param rPose1 first pose - * @param rPose2 second pose - */ - void SetTransform(const Pose2 &rPose1, const Pose2 &rPose2) { - if (rPose1 == rPose2) { - m_Rotation.SetToIdentity(); - m_InverseRotation.SetToIdentity(); - m_Transform = Pose2(); - return; - } - - // heading transformation - m_Rotation.FromAxisAngle(0, 0, 1, - rPose2.GetHeading() - rPose1.GetHeading()); - m_InverseRotation.FromAxisAngle(0, 0, 1, - rPose1.GetHeading() - rPose2.GetHeading()); - - // position transformation - Pose2 newPosition; - if (rPose1.GetX() != 0.0 || rPose1.GetY() != 0.0) { - newPosition = rPose2 - m_Rotation * rPose1; - } else { - newPosition = rPose2; - } - - m_Transform = Pose2(newPosition.GetPosition(), - rPose2.GetHeading() - rPose1.GetHeading()); - } - -private: - // pose transformation - Pose2 m_Transform; - - Matrix3 m_Rotation; - Matrix3 m_InverseRotation; -}; // Transform - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -/** - * Enumerated type for valid LaserRangeFinder types - */ -typedef enum { - LaserRangeFinder_Custom = 0, - - LaserRangeFinder_Sick_LMS100 = 1, - LaserRangeFinder_Sick_LMS200 = 2, - LaserRangeFinder_Sick_LMS291 = 3, - - LaserRangeFinder_Hokuyo_UTM_30LX = 4, - LaserRangeFinder_Hokuyo_URG_04LX = 5 -} LaserRangeFinderType; - -#endif diff --git a/include/Vector2.h b/include/Vector2.h deleted file mode 100644 index caa96c0..0000000 --- a/include/Vector2.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef VECTOR2_H -#define VECTOR2_H - -#include -#include -#include "AdditionalMath.h" - -template class Vector2 { -public: - /** - * Default constructor - */ - Vector2() { - m_Values[0] = 0; - m_Values[1] = 0; - } - - /** - * Constructor initializing vector location - * @param x - * @param y - */ - Vector2(T x, T y) { - m_Values[0] = x; - m_Values[1] = y; - } - -public: - /** - * Gets the x-coordinate of this vector2 - * @return the x-coordinate of the vector2 - */ - inline const T &GetX() const { return m_Values[0]; } - - /** - * Sets the x-coordinate of this vector2 - * @param x the x-coordinate of the vector2 - */ - inline void SetX(const T &x) { m_Values[0] = x; } - - /** - * Gets the y-coordinate of this vector2 - * @return the y-coordinate of the vector2 - */ - inline const T &GetY() const { return m_Values[1]; } - - /** - * Sets the y-coordinate of this vector2 - * @param y the y-coordinate of the vector2 - */ - inline void SetY(const T &y) { m_Values[1] = y; } - - /** - * Floor point operator - * @param rOther - */ - inline void MakeFloor(const Vector2 &rOther) { - if (rOther.m_Values[0] < m_Values[0]) - m_Values[0] = rOther.m_Values[0]; - if (rOther.m_Values[1] < m_Values[1]) - m_Values[1] = rOther.m_Values[1]; - } - - /** - * Ceiling point operator - * @param rOther - */ - inline void MakeCeil(const Vector2 &rOther) { - if (rOther.m_Values[0] > m_Values[0]) - m_Values[0] = rOther.m_Values[0]; - if (rOther.m_Values[1] > m_Values[1]) - m_Values[1] = rOther.m_Values[1]; - } - - /** - * Returns the square of the length of the vector - * @return square of the length of the vector - */ - inline double SquaredLength() const { - return amath::Square(m_Values[0]) + amath::Square(m_Values[1]); - } - - /** - * Returns the length of the vector (x and y). - * @return length of the vector - */ - inline double Length() const { return sqrt(SquaredLength()); } - - /** - * Returns the square distance to the given vector - * @returns square distance to the given vector - */ - inline double SquaredDistance(const Vector2 &rOther) const { - return (*this - rOther).SquaredLength(); - } - - /** - * Gets the distance to the other vector2 - * @param rOther - * @return distance to other vector2 - */ - inline double Distance(const Vector2 &rOther) const { - return sqrt(SquaredDistance(rOther)); - } - -public: - /** - * In place Vector2 addition. - */ - inline void operator+=(const Vector2 &rOther) { - m_Values[0] += rOther.m_Values[0]; - m_Values[1] += rOther.m_Values[1]; - } - - /** - * In place Vector2 subtraction. - */ - inline void operator-=(const Vector2 &rOther) { - m_Values[0] -= rOther.m_Values[0]; - m_Values[1] -= rOther.m_Values[1]; - } - - /** - * Addition operator - * @param rOther - * @return vector resulting from adding this vector with the given vector - */ - inline const Vector2 operator+(const Vector2 &rOther) const { - return Vector2(m_Values[0] + rOther.m_Values[0], - m_Values[1] + rOther.m_Values[1]); - } - - /** - * Subtraction operator - * @param rOther - * @return vector resulting from subtracting this vector from the given vector - */ - inline const Vector2 operator-(const Vector2 &rOther) const { - return Vector2(m_Values[0] - rOther.m_Values[0], - m_Values[1] - rOther.m_Values[1]); - } - - /** - * In place scalar division operator - * @param scalar - */ - inline void operator/=(T scalar) { - m_Values[0] /= scalar; - m_Values[1] /= scalar; - } - - /** - * Divides a Vector2 - * @param scalar - * @return scalar product - */ - inline const Vector2 operator/(T scalar) const { - return Vector2(m_Values[0] / scalar, m_Values[1] / scalar); - } - - /** - * Computes the dot product between the two vectors - * @param rOther - * @return dot product - */ - inline double operator*(const Vector2 &rOther) const { - return m_Values[0] * rOther.m_Values[0] + m_Values[1] * rOther.m_Values[1]; - } - - /** - * Scales the vector by the given scalar - * @param scalar - */ - inline const Vector2 operator*(T scalar) const { - return Vector2(m_Values[0] * scalar, m_Values[1] * scalar); - } - - /** - * Subtract the vector by the given scalar - * @param scalar - */ - inline const Vector2 operator-(T scalar) const { - return Vector2(m_Values[0] - scalar, m_Values[1] - scalar); - } - - /** - * In place scalar multiplication operator - * @param scalar - */ - inline void operator*=(T scalar) { - m_Values[0] *= scalar; - m_Values[1] *= scalar; - } - - /** - * Equality operator returns true if the corresponding x, y values of each - * Vector2 are the same values. - * @param rOther - */ - inline bool operator==(const Vector2 &rOther) const { - return (m_Values[0] == rOther.m_Values[0] && - m_Values[1] == rOther.m_Values[1]); - } - - /** - * Inequality operator returns true if any of the corresponding x, y values of - * each Vector2 not the same. - * @param rOther - */ - inline bool operator!=(const Vector2 &rOther) const { - return (m_Values[0] != rOther.m_Values[0] || - m_Values[1] != rOther.m_Values[1]); - } - - /** - * Less than operator - * @param rOther - * @return true if left vector is less than right vector - */ - inline bool operator<(const Vector2 &rOther) const { - if (m_Values[0] < rOther.m_Values[0]) - return true; - else if (m_Values[0] > rOther.m_Values[0]) - return false; - else - return (m_Values[1] < rOther.m_Values[1]); - } - - /** - * Write Vector2 onto output stream - * @param rStream output stream - * @param rVector to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Vector2 &rVector) { - rStream << rVector.GetX() << " " << rVector.GetY(); - return rStream; - } - - /** - * Read Vector2 from input stream - * @param rStream input stream - */ - friend inline std::istream &operator>>(std::istream &rStream, - const Vector2 & /*rVector*/) { - // Implement me!! TODO(lucbettaieb): What the what? Do I need to implement - // this? - return rStream; - } - -private: - T m_Values[2]; -}; // Vector2 - -/** - * Type declaration of Vector2 vector - */ -typedef std::vector> PointVectorDouble; - -#endif diff --git a/include/Vector3.h b/include/Vector3.h deleted file mode 100644 index 16dcc13..0000000 --- a/include/Vector3.h +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef VECTOR3_H -#define VECTOR3_H - -#include -#include "AdditionalMath.h" - -template class Vector3 { -public: - /** - * Default constructor - */ - Vector3() { - m_Values[0] = 0; - m_Values[1] = 0; - m_Values[2] = 0; - } - - /** - * Constructor initializing point location - * @param x - * @param y - * @param z - */ - Vector3(T x, T y, T z) { - m_Values[0] = x; - m_Values[1] = y; - m_Values[2] = z; - } - - /** - * Copy constructor - * @param rOther - */ - Vector3(const Vector3 &rOther) { - m_Values[0] = rOther.m_Values[0]; - m_Values[1] = rOther.m_Values[1]; - m_Values[2] = rOther.m_Values[2]; - } - -public: - /** - * Gets the x-component of this vector - * @return x-component - */ - inline const T &GetX() const { return m_Values[0]; } - - /** - * Sets the x-component of this vector - * @param x - */ - inline void SetX(const T &x) { m_Values[0] = x; } - - /** - * Gets the y-component of this vector - * @return y-component - */ - inline const T &GetY() const { return m_Values[1]; } - - /** - * Sets the y-component of this vector - * @param y - */ - inline void SetY(const T &y) { m_Values[1] = y; } - - /** - * Gets the z-component of this vector - * @return z-component - */ - inline const T &GetZ() const { return m_Values[2]; } - - /** - * Sets the z-component of this vector - * @param z - */ - inline void SetZ(const T &z) { m_Values[2] = z; } - - /** - * Floor vector operator - * @param rOther Vector3d - */ - inline void MakeFloor(const Vector3 &rOther) { - if (rOther.m_Values[0] < m_Values[0]) - m_Values[0] = rOther.m_Values[0]; - if (rOther.m_Values[1] < m_Values[1]) - m_Values[1] = rOther.m_Values[1]; - if (rOther.m_Values[2] < m_Values[2]) - m_Values[2] = rOther.m_Values[2]; - } - - /** - * Ceiling vector operator - * @param rOther Vector3d - */ - inline void MakeCeil(const Vector3 &rOther) { - if (rOther.m_Values[0] > m_Values[0]) - m_Values[0] = rOther.m_Values[0]; - if (rOther.m_Values[1] > m_Values[1]) - m_Values[1] = rOther.m_Values[1]; - if (rOther.m_Values[2] > m_Values[2]) - m_Values[2] = rOther.m_Values[2]; - } - - /** - * Returns the square of the length of the vector - * @return square of the length of the vector - */ - inline double SquaredLength() const { - return amath::Square(m_Values[0]) + amath::Square(m_Values[1]) + - amath::Square(m_Values[2]); - } - - /** - * Returns the length of the vector. - * @return Length of the vector - */ - inline double Length() const { return sqrt(SquaredLength()); } - - /** - * Returns a string representation of this vector - * @return string representation of this vector - */ - inline std::string ToString() const { - // std::stringstream converter; - // converter.precision(std::numeric_limits::digits10); - - // converter << GetX() << " " << GetY() << " " << GetZ(); - - // return converter.str(); - return "Notimplemented"; - } - -public: - /** - * Assignment operator - */ - inline Vector3 &operator=(const Vector3 &rOther) { - m_Values[0] = rOther.m_Values[0]; - m_Values[1] = rOther.m_Values[1]; - m_Values[2] = rOther.m_Values[2]; - - return *this; - } - - /** - * Binary vector add. - * @param rOther - * @return vector sum - */ - inline const Vector3 operator+(const Vector3 &rOther) const { - return Vector3(m_Values[0] + rOther.m_Values[0], - m_Values[1] + rOther.m_Values[1], - m_Values[2] + rOther.m_Values[2]); - } - - /** - * Binary vector add. - * @param scalar - * @return sum - */ - inline const Vector3 operator+(double scalar) const { - return Vector3(m_Values[0] + scalar, m_Values[1] + scalar, - m_Values[2] + scalar); - } - - /** - * Binary vector subtract. - * @param rOther - * @return vector difference - */ - inline const Vector3 operator-(const Vector3 &rOther) const { - return Vector3(m_Values[0] - rOther.m_Values[0], - m_Values[1] - rOther.m_Values[1], - m_Values[2] - rOther.m_Values[2]); - } - - /** - * Binary vector subtract. - * @param scalar - * @return difference - */ - inline const Vector3 operator-(double scalar) const { - return Vector3(m_Values[0] - scalar, m_Values[1] - scalar, - m_Values[2] - scalar); - } - - /** - * Scales the vector by the given scalar - * @param scalar - */ - inline const Vector3 operator*(T scalar) const { - return Vector3(m_Values[0] * scalar, m_Values[1] * scalar, - m_Values[2] * scalar); - } - - /** - * Equality operator returns true if the corresponding x, y, z values of each - * Vector3 are the same values. - * @param rOther - */ - inline bool operator==(const Vector3 &rOther) const { - return (m_Values[0] == rOther.m_Values[0] && - m_Values[1] == rOther.m_Values[1] && - m_Values[2] == rOther.m_Values[2]); - } - - /** - * Inequality operator returns true if any of the corresponding x, y, z values - * of each Vector3 not the same. - * @param rOther - */ - inline bool operator!=(const Vector3 &rOther) const { - return (m_Values[0] != rOther.m_Values[0] || - m_Values[1] != rOther.m_Values[1] || - m_Values[2] != rOther.m_Values[2]); - } - - /** - * Write Vector3 onto output stream - * @param rStream output stream - * @param rVector to write - */ - friend inline std::ostream &operator<<(std::ostream &rStream, - const Vector3 &rVector) { - rStream << rVector.ToString(); - return rStream; - } - - /** - * Read Vector3 from input stream - * @param rStream input stream - */ - friend inline std::istream &operator>>(std::istream &rStream, - const Vector3 & /*rVector*/) { - // Implement me!! - return rStream; - } - -private: - T m_Values[3]; -}; // Vector3 - -#endif diff --git a/ros1/slam_node_ros1 b/ros1/slam_node_ros1 index 3863b4f..1db22cd 100755 --- a/ros1/slam_node_ros1 +++ b/ros1/slam_node_ros1 @@ -4,7 +4,7 @@ import rospy from yag_slam.graph_slam import GraphSlam, make_near_scan_visitor from yag_slam.scan_matching import Scan2DMatcherCpp from yag_slam.graph import do_breadth_first_traversal -from yag_slam_cpp import create_occupancy_grid, Pose2 +from karto_scanmatcher import create_occupancy_grid, Pose2 from yag_slam.models import LocalizedRangeScan from yag_slam.splicing import map_to_graph from tiny_tf.tf import Transform diff --git a/run_docker.sh b/run_docker.sh deleted file mode 100755 index ad946b8..0000000 --- a/run_docker.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -source ~/catkin_ws/install/setup.bash -cd ~/catkin_ws/src/yag-slam/ros1/ -./slam_node_ros1 "$@" \ No newline at end of file diff --git a/setup.py b/setup.py index 69a24dc..431a224 100644 --- a/setup.py +++ b/setup.py @@ -15,19 +15,9 @@ from setuptools import setup, find_packages -try: - import pybind11_cmake -except ImportError: - print("pybind11-cmake must be installed." "Try \n \t pip install pybind11_cmake") - import sys - - sys.exit() - -from pybind11_cmake import CMakeExtension, CMakeBuild - setup( name="yag_slam", - version="0.2.5", + version="0.3.0", author="Jariullah Safi", author_email="safijari@isu.edu", description="A complete 2D and 3D graph SLAM implementation using plagiarized code from SRI's OpenKarto", @@ -53,10 +43,8 @@ "scikit-image", "tqdm", "threeviz", + "karto_scanmatcher==1.0.0", ], - setup_requires=["pybind11_cmake"], - ext_modules=[CMakeExtension("yag_slam_cpp")], - cmdclass=dict(build_ext=CMakeBuild), scripts=["ros1/slam_node_ros1"], zip_safe=False, ) diff --git a/src/Impls.cpp b/src/Impls.cpp deleted file mode 100644 index b261b6e..0000000 --- a/src/Impls.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2010 SRI International - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/* Modified 2019 by Jariullah Safi */ - - -#include "SensorData.h" -#include "OccupancyGrid.h" - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -SensorData::SensorData(const Name &rSensorName) - : Object(), m_StateId(-1), m_UniqueId(-1), m_SensorName(rSensorName), - m_Time(0.0) {} - -SensorData::~SensorData() { - for (auto iter : m_CustomData) { delete iter; } - - m_CustomData.clear(); -} -#include "Object.h" - -Object::Object() {} - -Object::Object(const Name &rName) : m_Name(rName) {} - -Object::~Object() {} - - - //////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////// - - void CellUpdater::operator() (uint32_t index) - { - uint8_t* pDataPtr = m_pOccupancyGrid->GetDataPointer(); - uint32_t* pCellPassCntPtr = m_pOccupancyGrid->m_pCellPassCnt->GetDataPointer(); - uint32_t* pCellHitCntPtr = m_pOccupancyGrid->m_pCellHitsCnt->GetDataPointer(); - - m_pOccupancyGrid->UpdateCell(&pDataPtr[index], pCellPassCntPtr[index], pCellHitCntPtr[index]); - } diff --git a/src/PythonInterface.cpp b/src/PythonInterface.cpp deleted file mode 100644 index 137ea6c..0000000 --- a/src/PythonInterface.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2019 Jariullah Safi - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#include "Grid.h" -#include "LocalizedRangeScan.h" -#include "OccupancyGrid.h" -#include "ScanMatcher.h" - -namespace py = pybind11; - -struct MatchResult { - Pose2 best_pose; - Matrix3 covariance; - double response; -}; - -class Wrapper { - Name name; - -public: - std::shared_ptr config; - ScanMatcher *matcher; - - Wrapper(std::shared_ptr config) { - this->config = config; - this->matcher = ScanMatcher::Create(config); - } - - MatchResult MatchScan(LocalizedRangeScan *query, - const LocalizedRangeScanVector &base, - bool penalize = true, bool refine = true) { - py::gil_scoped_release release; - Pose2 mean; - Matrix3 covariance; - auto ret = this->matcher->MatchScan(query, base, mean, covariance, penalize, - refine); - return MatchResult{mean, covariance, ret}; - } - - ~Wrapper() { delete this->matcher; } -}; - -OccupancyGrid *CreateOccupancyGrid(LocalizedRangeScanVector *scans, - double resolution, double rangeThreshold) { - py::gil_scoped_release release; - auto pOccupancyGrid = OccupancyGrid::CreateFromScans(*scans, resolution, rangeThreshold); - return pOccupancyGrid; -} - -PYBIND11_MODULE(yag_slam_cpp, m) { - py::class_(m, "Pose2") - .def(py::init()) - .def_property("x", &Pose2::GetX, &Pose2::SetX) - .def_property("y", &Pose2::GetY, &Pose2::SetY) - .def_property("yaw", &Pose2::GetHeading, &Pose2::SetHeading) - .def("__repr__", [](const Pose2 &a) { - std::stringstream buffer; - buffer << "(x: " << a.GetX() << ", y: " << a.GetY() - << ", heading: " << a.GetHeading() << ")\n"; - return buffer.str(); - }); - - py::class_>(m, "Vec2_d") - .def(py::init()) - .def_property("x", &Vector2::GetX, &Vector2::SetX) - .def_property("y", &Vector2::GetY, &Vector2::SetY); - - py::class_(m, "Name").def(py::init()); - - py::class_(m, "LocalizedRangeScan") - .def(py::init, Pose2, Pose2, - uint32_t, double>()) - .def_readonly("config", &LocalizedRangeScan::config) - .def_property_readonly("ranges", - &LocalizedRangeScan::GetRangeReadingsVector) - .def_property("odom_pose", &LocalizedRangeScan::GetOdometricPose, - &LocalizedRangeScan::SetOdometricPose) - .def_property("corrected_pose", &LocalizedRangeScan::GetCorrectedPose, - &LocalizedRangeScan::SetCorrectedPose) - .def_property("num", &LocalizedRangeScan::GetUniqueId, - &LocalizedRangeScan::SetUniqueId) - .def_property("time", &LocalizedRangeScan::GetTime, - &LocalizedRangeScan::SetTime); - - py::class_(m, "Wrapper") - .def(py::init>()) - .def_readonly("config", &Wrapper::config) - .def("match_scan", &Wrapper::MatchScan, - py::return_value_policy::reference) - .def("grid", [](const Wrapper &a_) { - auto a = a_.matcher->GetCorrelationGrid(); - auto roi = a->GetROI(); - auto h = roi.GetHeight(); - auto w = roi.GetWidth(); - auto _r = py::array_t({h, w}); - auto r = _r.mutable_unchecked<2>(); - for (auto j = 0; j < h; j++) { - for (auto i = 0; i < w; i++) { - auto idx = a->GridIndex(Vector2(i, j)); - uint8_t *pByte = a->GetDataPointer() + idx; - r(j, i) = pByte[0]; - } - } - return _r; - }, py::return_value_policy::reference) - ; - - py::class_(m, "MatchResult") - .def_readwrite("best_pose", &MatchResult::best_pose) - .def_property_readonly("covariance", - [](const MatchResult &a) { - auto ret = std::vector>(3); - for (int j = 0; j < 3; j++) { - for (int i = 0; i < 3; i++) { - ret[j].push_back( - a.covariance.m_Matrix[j][i]); - } - } - - return ret; - }) - .def_readwrite("response", &MatchResult::response); - - py::class_>( - m, "ScanMatcherConfig") - .def(py::init<>()) - .def_readwrite("coarse_angle_resolution", - &ScanMatcherConfig::m_pCoarseAngleResolution) - .def_readwrite("coarse_search_angle_offset", - &ScanMatcherConfig::m_pCoarseSearchAngleOffset) - .def_readwrite("fine_search_angle_resolution", - &ScanMatcherConfig::m_pFineSearchAngleResolution) - .def_readwrite("distance_variance_penalty", - &ScanMatcherConfig::m_pDistanceVariancePenalty) - .def_readwrite("angle_variance_penalty", - &ScanMatcherConfig::m_pAngleVariancePenalty) - .def_readwrite("minimum_distance_penalty", - &ScanMatcherConfig::m_pMinimumDistancePenalty) - .def_readwrite("minimum_angle_penalty", - &ScanMatcherConfig::m_pMinimumAnglePenalty) - .def_readwrite("use_response_expansion", - &ScanMatcherConfig::m_pUseResponseExpansion) - .def_readwrite("search_size", &ScanMatcherConfig::searchSize) - .def_readwrite("resolution", &ScanMatcherConfig::resolution) - .def_readwrite("smear_deviation", &ScanMatcherConfig::smearDeviation) - .def_readwrite("range_threshold", &ScanMatcherConfig::rangeThreshold); - - m.def("create_occupancy_grid", &CreateOccupancyGrid); - - py::class_>( - m, "LaserScanConfig") - .def(py::init()) - .def_readonly("min_angle", &LaserScanConfig::minAngle) - .def_readonly("max_angle", &LaserScanConfig::maxAngle) - .def_readonly("angular_resolution", &LaserScanConfig::angularResolution) - .def_readonly("min_range", &LaserScanConfig::minRange) - .def_readonly("max_range", &LaserScanConfig::maxRange) - .def_readonly("min_angle", &LaserScanConfig::minAngle) - .def_readonly("range_threshold", &LaserScanConfig::rangeThreshold) - .def_readonly("sensor_name", &LaserScanConfig::sensorName); - - py::enum_(m, "GridStates") - .value("Unknown", GridStates::GridStates_Unknown) - .value("Occupied", GridStates::GridStates_Occupied) - .value("Free", GridStates::GridStates_Free); - - py::class_(m, "OccupancyGrid") - .def_property_readonly("width", &OccupancyGrid::GetWidth) - .def_property_readonly("height", &OccupancyGrid::GetHeight) - .def_property_readonly("offset", - [](const OccupancyGrid &a) { - auto offset = - (a.GetCoordinateConverter()->GetOffset()); - return offset; - }) - .def("get_value", [](const OccupancyGrid &a, int32_t x, int32_t y) { - return a.GetValue(Vector2(x, y)); - }) - .def_property_readonly("image", [](const OccupancyGrid &a) { - auto h = a.GetHeight(); - auto w = a.GetWidth(); - auto _r = py::array_t({h, w}); - auto r = _r.mutable_unchecked<2>(); - for (auto j = 0; j < h; j++) { - for (auto i = 0; i < w; i++) { - // free was 255 - // occupied was 100 - // unknown was 0 - auto val = a.GetValue(Vector2(w - i - 1, j)); - if (val == 0) { val = 200; } else if (val == 100) { val = 0; } - // free is 255 - // unknown is 200 - // occupied is 0 - r(j, w - i - 1) = val; - } - } - return _r; - }) - ; - -#ifdef VERSION_INFO - m.attr("__version__") = VERSION_INFO; -#else - m.attr("__version__") = "dev"; -#endif -} diff --git a/src/ScanMatcher.cpp b/src/ScanMatcher.cpp deleted file mode 100644 index 0e362c8..0000000 --- a/src/ScanMatcher.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright 2010 SRI International - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/* Modified 2019 by Jariullah Safi */ - -#include -#include "ScanMatcher.h" -#include "AdditionalMath.h" -#include -#include "CorrelationGrid.h" - -ScanMatcher::~ScanMatcher() { - delete m_pCorrelationGrid; - delete m_pSearchSpaceProbs; - delete m_pGridLookup; -} - -ScanMatcher *ScanMatcher::Create(std::shared_ptr config) { - - double resolution = config->resolution; - // invalid parameters - if (resolution <= 0) { - return NULL; - } - - double searchSize = config->searchSize; - if (searchSize <= 0) { - return NULL; - } - - double smearDeviation = config->smearDeviation; - if (smearDeviation < 0) { - return NULL; - } - - double rangeThreshold = config->rangeThreshold; - if (rangeThreshold <= 0) { - return NULL; - } - - assert(amath::DoubleEqual(amath::Round(searchSize / resolution), - (searchSize / resolution))); - - // calculate search space in grid coordinates - int32_t searchSpaceSideSize = - static_cast(amath::Round(searchSize / resolution) + 1); - - // compute requisite size of correlation grid (pad grid so that scan points - // can't fall off the grid if a scan is on the border of the search space) - int32_t pointReadingMargin = - static_cast(ceil(rangeThreshold / resolution)); - - int32_t gridSize = searchSpaceSideSize + 2 * pointReadingMargin; - - // create correlation grid - assert(gridSize % 2 == 1); - CorrelationGrid *pCorrelationGrid = CorrelationGrid::CreateGrid( - gridSize, gridSize, resolution, smearDeviation); - - // create search space probabilities - Grid *pSearchSpaceProbs = Grid::CreateGrid( - searchSpaceSideSize, searchSpaceSideSize, resolution); - - ScanMatcher *pScanMatcher = new ScanMatcher(config); - pScanMatcher->m_pCorrelationGrid = pCorrelationGrid; - pScanMatcher->m_pSearchSpaceProbs = pSearchSpaceProbs; - pScanMatcher->m_pGridLookup = new GridIndexLookup(pCorrelationGrid); - - return pScanMatcher; -} - -/** - * Match given scan against set of scans - * @param pScan scan being scan-matched - * @param rBaseScans set of scans whose points will mark cells in grid as being - * occupied - * @param rMean output parameter of mean (best pose) of match - * @param rCovariance output parameter of covariance of match - * @param doPenalize whether to penalize matches further from the search center - * @param doRefineMatch whether to do finer-grained matching if coarse match is - * good (default is true) - * @return strength of response - */ -double ScanMatcher::MatchScan(LocalizedRangeScan *pScan, - const LocalizedRangeScanVector &rBaseScans, - Pose2 &rMean, Matrix3 &rCovariance, - bool doPenalize, bool doRefineMatch) { - /////////////////////////////////////// - // set scan pose to be center of grid - - // TODO Below needs to be handled elsewhere, not ScanMatcher's business - // 1. get scan position - Pose2 scanPose = pScan->GetCorrectedPose(); - - // scan has no readings; cannot do scan matching - // best guess of pose is based off of adjusted odometer reading - if (pScan->GetNumberOfRangeReadings() == 0) { - rMean = scanPose; - - // maximum covariance - rCovariance(0, 0) = MAX_VARIANCE; // XX - rCovariance(1, 1) = MAX_VARIANCE; // YY - rCovariance(2, 2) = - 4 * - amath::Square(config->m_pCoarseAngleResolution); // TH*TH - - return 0.0; - } - - // 2. get size of grid - Rectangle2 roi = m_pCorrelationGrid->GetROI(); - - // 3. compute offset (in meters - lower left corner) - Vector2 offset; - offset.SetX(scanPose.GetX() - (0.5 * (roi.GetWidth() - 1) * - m_pCorrelationGrid->GetResolution())); - offset.SetY(scanPose.GetY() - (0.5 * (roi.GetHeight() - 1) * - m_pCorrelationGrid->GetResolution())); - - // 4. set offset - m_pCorrelationGrid->GetCoordinateConverter()->SetOffset(offset); - - /////////////////////////////////////// - - // set up correlation grid - AddScans(rBaseScans, scanPose.GetPosition()); - - // compute how far to search in each direction - Vector2 searchDimensions(m_pSearchSpaceProbs->GetWidth(), - m_pSearchSpaceProbs->GetHeight()); - - Vector2 coarseSearchOffset( - 0.5 * (searchDimensions.GetX() - 1) * m_pCorrelationGrid->GetResolution(), - 0.5 * (searchDimensions.GetY() - 1) * - m_pCorrelationGrid->GetResolution()); - - // a coarse search only checks half the cells in each dimension - Vector2 coarseSearchResolution( - 2 * m_pCorrelationGrid->GetResolution(), - 2 * m_pCorrelationGrid->GetResolution()); - - // actual scan-matching - double bestResponse = - CorrelateScan(pScan, scanPose, coarseSearchOffset, coarseSearchResolution, - config->m_pCoarseSearchAngleOffset, - config->m_pCoarseAngleResolution, doPenalize, - rMean, rCovariance, false); - - if (config->m_pUseResponseExpansion == true) { - if (amath::DoubleEqual(bestResponse, 0.0)) { -#ifdef KARTO_DEBUG - std::cout << "Mapper Info: Expanding response search space!" << std::endl; -#endif - // try and increase search angle offset with 20 degrees and do another - // match - double newSearchAngleOffset = - config->m_pCoarseSearchAngleOffset; - for (int32_t i = 0; i < 3; i++) { - newSearchAngleOffset += amath::DegreesToRadians(20); - - bestResponse = - CorrelateScan(pScan, scanPose, coarseSearchOffset, - coarseSearchResolution, newSearchAngleOffset, - config->m_pCoarseAngleResolution, - doPenalize, rMean, rCovariance, false); - - if (amath::DoubleEqual(bestResponse, 0.0) == false) { - break; - } - } - - -#ifdef KARTO_DEBUG - if (amath::DoubleEqual(bestResponse, 0.0)) { - std::cout << "Mapper Warning: Unable to calculate response!" - << std::endl; - } -#endif - } - } - - if (doRefineMatch) { - Vector2 fineSearchOffset(coarseSearchResolution * 0.5); - Vector2 fineSearchResolution( - m_pCorrelationGrid->GetResolution(), - m_pCorrelationGrid->GetResolution()); - bestResponse = - CorrelateScan(pScan, rMean, fineSearchOffset, fineSearchResolution, - 0.5 * config->m_pCoarseAngleResolution, - config->m_pFineSearchAngleResolution, - doPenalize, rMean, rCovariance, true); - } - - - -#ifdef KARTO_DEBUG - std::cout << " BEST POSE = " << rMean << " BEST RESPONSE = " << bestResponse - << ", VARIANCE = " << rCovariance(0, 0) << ", " - << rCovariance(1, 1) << std::endl; -#endif - assert(amath::InRange(rMean.GetHeading(), -KT_PI, KT_PI)); - - - return bestResponse; -} - -/** - * Finds the best pose for the scan centering the search in the correlation grid - * at the given pose and search in the space by the vector and angular offsets - * in increments of the given resolutions - * @param rScan scan to match against correlation grid - * @param rSearchCenter the center of the search space - * @param rSearchSpaceOffset searches poses in the area offset by this vector - * around search center - * @param rSearchSpaceResolution how fine a granularity to search in the search - * space - * @param searchAngleOffset searches poses in the angles offset by this angle - * around search center - * @param searchAngleResolution how fine a granularity to search in the angular - * search space - * @param doPenalize whether to penalize matches further from the search center - * @param rMean output parameter of mean (best pose) of match - * @param rCovariance output parameter of covariance of match - * @param doingFineMatch whether to do a finer search after coarse search - * @return strength of response - */ -double ScanMatcher::CorrelateScan( - LocalizedRangeScan *pScan, const Pose2 &rSearchCenter, - const Vector2 &rSearchSpaceOffset, - const Vector2 &rSearchSpaceResolution, - double searchAngleOffset, double searchAngleResolution, - bool doPenalize, Pose2 &rMean, Matrix3 &rCovariance, - bool doingFineMatch) { - assert(searchAngleResolution != 0.0); - - - // setup lookup arrays - m_pGridLookup->ComputeOffsets(pScan, rSearchCenter.GetHeading(), - searchAngleOffset, searchAngleResolution); - - - - // only initialize probability grid if computing positional covariance (during - // coarse match) - if (!doingFineMatch) { - m_pSearchSpaceProbs->Clear(); - - // position search grid - finds lower left corner of search grid - Vector2 offset(rSearchCenter.GetPosition() - rSearchSpaceOffset); - m_pSearchSpaceProbs->GetCoordinateConverter()->SetOffset(offset); - } - - // calculate position arrays - - - std::vector xPoses; - int32_t nX = - static_cast(amath::Round(rSearchSpaceOffset.GetX() * 2.0 / - rSearchSpaceResolution.GetX()) + - 1); - - double startX = -rSearchSpaceOffset.GetX(); - for (int32_t xIndex = 0; xIndex < nX; xIndex++) { - xPoses.push_back(startX + xIndex * rSearchSpaceResolution.GetX()); - } - assert(amath::DoubleEqual(xPoses.back(), -startX)); - - - std::vector yPoses; - int32_t nY = - static_cast(amath::Round(rSearchSpaceOffset.GetY() * 2.0 / - rSearchSpaceResolution.GetY()) + - 1); - double startY = -rSearchSpaceOffset.GetY(); - for (int32_t yIndex = 0; yIndex < nY; yIndex++) { - yPoses.push_back(startY + yIndex * rSearchSpaceResolution.GetY()); - } - - - assert(amath::DoubleEqual(yPoses.back(), -startY)); - - // calculate pose response array size - int32_t nAngles = static_cast( - amath::Round(searchAngleOffset * 2.0 / searchAngleResolution) + 1); - - int32_t poseResponseSize = - static_cast(xPoses.size() * yPoses.size() * nAngles); - - // allocate array - std::pair *pPoseResponse = - new std::pair[poseResponseSize]; - - Vector2 startGridPoint = - m_pCorrelationGrid->WorldToGrid(Vector2( - rSearchCenter.GetX() + startX, rSearchCenter.GetY() + startY)); - - int32_t poseResponseCounter = 0; - for (auto yIter : yPoses) { - double y = yIter; - double newPositionY = rSearchCenter.GetY() + y; - double squareY = amath::Square(y); - - for (auto xIter : xPoses) { - double x = xIter; - double newPositionX = rSearchCenter.GetX() + x; - double squareX = amath::Square(x); - - Vector2 gridPoint = m_pCorrelationGrid->WorldToGrid( - Vector2(newPositionX, newPositionY)); - int32_t gridIndex = m_pCorrelationGrid->GridIndex(gridPoint); - assert(gridIndex >= 0); - - double angle = 0.0; - double startAngle = rSearchCenter.GetHeading() - searchAngleOffset; - for (int32_t angleIndex = 0; angleIndex < nAngles; angleIndex++) { - angle = startAngle + angleIndex * searchAngleResolution; - - double response = GetResponse(angleIndex, gridIndex); - if (doPenalize && (amath::DoubleEqual(response, 0.0) == false)) { - // simple model (approximate Gaussian) to take odometry into account - - double squaredDistance = squareX + squareY; - double distancePenalty = - 1.0 - (DISTANCE_PENALTY_GAIN * squaredDistance / - config->m_pDistanceVariancePenalty); - distancePenalty = - amath::Maximum(distancePenalty, - config->m_pMinimumDistancePenalty); - - double squaredAngleDistance = - amath::Square(angle - rSearchCenter.GetHeading()); - double anglePenalty = - 1.0 - (ANGLE_PENALTY_GAIN * squaredAngleDistance / - config->m_pAngleVariancePenalty); - anglePenalty = amath::Maximum( - anglePenalty, config->m_pMinimumAnglePenalty); - - response *= (distancePenalty * anglePenalty); - } - - // store response and pose - pPoseResponse[poseResponseCounter] = std::pair( - response, - Pose2(newPositionX, newPositionY, amath::NormalizeAngle(angle))); - poseResponseCounter++; - } - - assert(amath::DoubleEqual(angle, - rSearchCenter.GetHeading() + searchAngleOffset)); - } - } - - assert(poseResponseSize == poseResponseCounter); - - // find value of best response (in [0; 1]) - double bestResponse = -1; - for (int32_t i = 0; i < poseResponseSize; i++) { - bestResponse = amath::Maximum(bestResponse, pPoseResponse[i].first); - - // will compute positional covariance, save best relative probability for - // each cell - if (!doingFineMatch) { - const Pose2 &rPose = pPoseResponse[i].second; - Vector2 grid = - m_pSearchSpaceProbs->WorldToGrid(rPose.GetPosition()); - - // Changed (double*) to the reinterpret_cast - Luc - double *ptr = reinterpret_cast( - m_pSearchSpaceProbs->GetDataPointer(grid)); - if (ptr == NULL) { - throw std::runtime_error( - "Mapper FATAL ERROR - Index out of range in probability search!"); - } - - *ptr = amath::Maximum(pPoseResponse[i].first, *ptr); - } - } - - // average all poses with same highest response - Vector2 averagePosition; - double thetaX = 0.0; - double thetaY = 0.0; - int32_t averagePoseCount = 0; - for (int32_t i = 0; i < poseResponseSize; i++) { - if (amath::DoubleEqual(pPoseResponse[i].first, bestResponse)) { - averagePosition += pPoseResponse[i].second.GetPosition(); - - double heading = pPoseResponse[i].second.GetHeading(); - thetaX += cos(heading); - thetaY += sin(heading); - - averagePoseCount++; - } - } - - Pose2 averagePose; - if (averagePoseCount > 0) { - averagePosition /= averagePoseCount; - - thetaX /= averagePoseCount; - thetaY /= averagePoseCount; - - averagePose = Pose2(averagePosition, atan2(thetaY, thetaX)); - } else { - throw std::runtime_error( - "Mapper FATAL ERROR - Unable to find best position"); - } - - // delete pose response array - delete[] pPoseResponse; - -#ifdef KARTO_DEBUG - std::cout << "bestPose: " << averagePose << std::endl; - std::cout << "bestResponse: " << bestResponse << std::endl; -#endif - - if (!doingFineMatch) { - ComputePositionalCovariance(averagePose, bestResponse, rSearchCenter, - rSearchSpaceOffset, rSearchSpaceResolution, - searchAngleResolution, rCovariance); - } else { - ComputeAngularCovariance(averagePose, bestResponse, rSearchCenter, - searchAngleOffset, searchAngleResolution, - rCovariance); - } - - rMean = averagePose; - -#ifdef KARTO_DEBUG - std::cout << "bestPose: " << averagePose << std::endl; -#endif - - if (bestResponse > 1.0) { - bestResponse = 1.0; - } - - assert(amath::InRange(bestResponse, 0.0, 1.0)); - assert(amath::InRange(rMean.GetHeading(), -KT_PI, KT_PI)); - - return bestResponse; -} - -/** - * Computes the positional covariance of the best pose - * @param rBestPose - * @param bestResponse - * @param rSearchCenter - * @param rSearchSpaceOffset - * @param rSearchSpaceResolution - * @param searchAngleResolution - * @param rCovariance - */ -void ScanMatcher::ComputePositionalCovariance( - const Pose2 &rBestPose, double bestResponse, const Pose2 &rSearchCenter, - const Vector2 &rSearchSpaceOffset, - const Vector2 &rSearchSpaceResolution, - double searchAngleResolution, Matrix3 &rCovariance) { - // reset covariance to identity matrix - rCovariance.SetToIdentity(); - - // if best response is vary small return max variance - if (bestResponse < KT_TOLERANCE) { - rCovariance(0, 0) = MAX_VARIANCE; // XX - rCovariance(1, 1) = MAX_VARIANCE; // YY - rCovariance(2, 2) = 4 * amath::Square(searchAngleResolution); // TH*TH - - return; - } - - double accumulatedVarianceXX = 0; - double accumulatedVarianceXY = 0; - double accumulatedVarianceYY = 0; - double norm = 0; - - double dx = rBestPose.GetX() - rSearchCenter.GetX(); - double dy = rBestPose.GetY() - rSearchCenter.GetY(); - - double offsetX = rSearchSpaceOffset.GetX(); - double offsetY = rSearchSpaceOffset.GetY(); - - int32_t nX = static_cast( - amath::Round(offsetX * 2.0 / rSearchSpaceResolution.GetX()) + 1); - double startX = -offsetX; - assert(amath::DoubleEqual(startX + (nX - 1) * rSearchSpaceResolution.GetX(), - -startX)); - - int32_t nY = static_cast( - amath::Round(offsetY * 2.0 / rSearchSpaceResolution.GetY()) + 1); - double startY = -offsetY; - assert(amath::DoubleEqual(startY + (nY - 1) * rSearchSpaceResolution.GetY(), - -startY)); - - for (int32_t yIndex = 0; yIndex < nY; yIndex++) { - double y = startY + yIndex * rSearchSpaceResolution.GetY(); - - for (int32_t xIndex = 0; xIndex < nX; xIndex++) { - double x = startX + xIndex * rSearchSpaceResolution.GetX(); - - Vector2 gridPoint = - m_pSearchSpaceProbs->WorldToGrid(Vector2( - rSearchCenter.GetX() + x, rSearchCenter.GetY() + y)); - double response = *(m_pSearchSpaceProbs->GetDataPointer(gridPoint)); - - // response is not a low response - if (response >= (bestResponse - 0.1)) { - norm += response; - accumulatedVarianceXX += (amath::Square(x - dx) * response); - accumulatedVarianceXY += ((x - dx) * (y - dy) * response); - accumulatedVarianceYY += (amath::Square(y - dy) * response); - } - } - } - - if (norm > KT_TOLERANCE) { - double varianceXX = accumulatedVarianceXX / norm; - double varianceXY = accumulatedVarianceXY / norm; - double varianceYY = accumulatedVarianceYY / norm; - double varianceTHTH = 4 * amath::Square(searchAngleResolution); - - // lower-bound variances so that they are not too small; - // ensures that links are not too tight - double minVarianceXX = 0.1 * amath::Square(rSearchSpaceResolution.GetX()); - double minVarianceYY = 0.1 * amath::Square(rSearchSpaceResolution.GetY()); - varianceXX = amath::Maximum(varianceXX, minVarianceXX); - varianceYY = amath::Maximum(varianceYY, minVarianceYY); - - // increase variance for poorer responses - double multiplier = 1.0 / bestResponse; - rCovariance(0, 0) = varianceXX * multiplier; - rCovariance(0, 1) = varianceXY * multiplier; - rCovariance(1, 0) = varianceXY * multiplier; - rCovariance(1, 1) = varianceYY * multiplier; - rCovariance(2, 2) = - varianceTHTH; // this value will be set in ComputeAngularCovariance - } - - // if values are 0, set to MAX_VARIANCE - // values might be 0 if points are too sparse and thus don't hit other points - if (amath::DoubleEqual(rCovariance(0, 0), 0.0)) { - rCovariance(0, 0) = MAX_VARIANCE; - } - - if (amath::DoubleEqual(rCovariance(1, 1), 0.0)) { - rCovariance(1, 1) = MAX_VARIANCE; - } -} - -/** - * Computes the angular covariance of the best pose - * @param rBestPose - * @param bestResponse - * @param rSearchCenter - * @param rSearchAngleOffset - * @param searchAngleResolution - * @param rCovariance - */ -void ScanMatcher::ComputeAngularCovariance(const Pose2 &rBestPose, - double bestResponse, - const Pose2 &rSearchCenter, - double searchAngleOffset, - double searchAngleResolution, - Matrix3 &rCovariance) { - // NOTE: do not reset covariance matrix - - // normalize angle difference - double bestAngle = amath::NormalizeAngleDifference( - rBestPose.GetHeading(), rSearchCenter.GetHeading()); - - Vector2 gridPoint = - m_pCorrelationGrid->WorldToGrid(rBestPose.GetPosition()); - int32_t gridIndex = m_pCorrelationGrid->GridIndex(gridPoint); - - int32_t nAngles = static_cast( - amath::Round(searchAngleOffset * 2 / searchAngleResolution) + 1); - - double angle = 0.0; - double startAngle = rSearchCenter.GetHeading() - searchAngleOffset; - - double norm = 0.0; - double accumulatedVarianceThTh = 0.0; - for (int32_t angleIndex = 0; angleIndex < nAngles; angleIndex++) { - angle = startAngle + angleIndex * searchAngleResolution; - double response = GetResponse(angleIndex, gridIndex); - - // response is not a low response - if (response >= (bestResponse - 0.1)) { - norm += response; - accumulatedVarianceThTh += (amath::Square(angle - bestAngle) * response); - } - } - assert( - amath::DoubleEqual(angle, rSearchCenter.GetHeading() + searchAngleOffset)); - - if (norm > KT_TOLERANCE) { - if (accumulatedVarianceThTh < KT_TOLERANCE) { - accumulatedVarianceThTh = amath::Square(searchAngleResolution); - } - - accumulatedVarianceThTh /= norm; - } else { - accumulatedVarianceThTh = 1000 * amath::Square(searchAngleResolution); - } - - rCovariance(2, 2) = accumulatedVarianceThTh; -} - -/** - * Marks cells where scans' points hit as being occupied - * @param rScans scans whose points will mark cells in grid as being occupied - * @param viewPoint do not add points that belong to scans "opposite" the view - * point - */ -void ScanMatcher::AddScans(const LocalizedRangeScanVector &rScans, - Vector2 viewPoint) { - m_pCorrelationGrid->Clear(); - - // add all scans to grid - // const_forEach(LocalizedRangeScanVector, &rScans) { - for (auto iter : rScans) { - AddScan(iter, viewPoint); - } -} - -/** - * Marks cells where scans' points hit as being occupied. Can smear points as - * they are added. - * @param pScan scan whose points will mark cells in grid as being occupied - * @param viewPoint do not add points that belong to scans "opposite" the view - * point - * @param doSmear whether the points will be smeared - */ -void ScanMatcher::AddScan(LocalizedRangeScan *pScan, - const Vector2 &rViewPoint, - bool doSmear) { - PointVectorDouble validPoints = FindValidPoints(pScan, rViewPoint); - - // put in all valid points - // const_forEach(PointVectorDouble, &validPoints) { - for (auto iter : validPoints) { - Vector2 gridPoint = m_pCorrelationGrid->WorldToGrid(iter); - if (!amath::IsUpTo(gridPoint.GetX(), - m_pCorrelationGrid->GetROI().GetWidth()) || - !amath::IsUpTo(gridPoint.GetY(), - m_pCorrelationGrid->GetROI().GetHeight())) { - // point not in grid - continue; - } - - int gridIndex = m_pCorrelationGrid->GridIndex(gridPoint); - - // set grid cell as occupied - if (m_pCorrelationGrid->GetDataPointer()[gridIndex] == - GridStates_Occupied) { - // value already set - continue; - } - - m_pCorrelationGrid->GetDataPointer()[gridIndex] = GridStates_Occupied; - - // smear grid - if (doSmear == true) { - m_pCorrelationGrid->SmearPoint(gridPoint); - } - } -} - -/** - * Compute which points in a scan are on the same side as the given viewpoint - * @param pScan - * @param rViewPoint - * @return points on the same side - */ -PointVectorDouble -ScanMatcher::FindValidPoints(LocalizedRangeScan *pScan, - const Vector2 &rViewPoint) const { - const PointVectorDouble &rPointReadings = pScan->GetPointReadings(); - - // points must be at least 10 cm away when making comparisons of - // inside/outside of viewpoint - const double minSquareDistance = amath::Square(0.1); // in m^2 - - // this iterator lags from the main iterator adding points only when the - // points are on the same side as the viewpoint - PointVectorDouble::const_iterator trailingPointIter = rPointReadings.begin(); - PointVectorDouble validPoints; - - Vector2 firstPoint; - bool firstTime = true; - // const_forEach(PointVectorDouble, &rPointReadings) { - for (auto iter = rPointReadings.begin(); iter < rPointReadings.end(); iter++) { - Vector2 currentPoint = *iter; - - if (firstTime && !std::isnan(currentPoint.GetX()) && - !std::isnan(currentPoint.GetY())) { - firstPoint = currentPoint; - firstTime = false; - } - - Vector2 delta = firstPoint - currentPoint; - if (delta.SquaredLength() > minSquareDistance) { - // This compute the Determinant (viewPoint FirstPoint, viewPoint - // currentPoint) Which computes the direction of rotation, if the rotation - // is counterclock wise then we are looking at data we should keep. If - // it's negative rotation we should not included in in the matching have - // enough distance, check viewpoint - double a = rViewPoint.GetY() - firstPoint.GetY(); - double b = firstPoint.GetX() - rViewPoint.GetX(); - double c = firstPoint.GetY() * rViewPoint.GetX() - - firstPoint.GetX() * rViewPoint.GetY(); - double ss = currentPoint.GetX() * a + currentPoint.GetY() * b + c; - - // reset beginning point - firstPoint = currentPoint; - - if (ss < 0.0) // wrong side, skip and keep going - { - trailingPointIter = iter; - } else { - for (; trailingPointIter != iter; ++trailingPointIter) { - validPoints.push_back(*trailingPointIter); - } - } - } - } - - return validPoints; -} - -/** - * Get response at given position for given rotation (only look up valid points) - * @param angleIndex - * @param gridPositionIndex - * @return response - */ -double ScanMatcher::GetResponse(int32_t angleIndex, - int32_t gridPositionIndex) const { - double response = 0.0; - - // add up value for each point - uint8_t *pByte = m_pCorrelationGrid->GetDataPointer() + gridPositionIndex; - - const LookupArray *pOffsets = m_pGridLookup->GetLookupArray(angleIndex); - assert(pOffsets != NULL); - - // get number of points in offset list - int32_t nPoints = pOffsets->GetSize(); - if (nPoints == 0) { - return response; - } - - // calculate response - int32_t *pAngleIndexPointer = pOffsets->GetArrayPointer(); - for (int32_t i = 0; i < nPoints; i++) { - // ignore points that fall off the grid - int32_t pointGridIndex = gridPositionIndex + pAngleIndexPointer[i]; - if (!amath::IsUpTo(pointGridIndex, m_pCorrelationGrid->GetDataSize()) || - pAngleIndexPointer[i] == INVALID_SCAN) { - continue; - } - - // uses index offsets to efficiently find location of point in the grid - response += pByte[pAngleIndexPointer[i]]; - } - - // normalize response - response /= (nPoints * GridStates_Occupied); - assert(fabs(response) <= 1.0); - - return response; -} diff --git a/test.py b/test.py index 2320252..f645c25 100644 --- a/test.py +++ b/test.py @@ -15,9 +15,9 @@ import numpy as np -from yag_slam_cpp import LocalizedRangeScan, LaserScanConfig, Pose2 +from karto_scanmatcher import LocalizedRangeScan, LaserScanConfig, Pose2 -from yag_slam_cpp import Wrapper, ScanMatcherConfig +from karto_scanmatcher import Wrapper, ScanMatcherConfig def main(): diff --git a/yag_slam/graph_slam.py b/yag_slam/graph_slam.py index 3313c25..77ead4d 100644 --- a/yag_slam/graph_slam.py +++ b/yag_slam/graph_slam.py @@ -15,7 +15,7 @@ from yag_slam.helpers import print_config, default_config, make_config, scans_dist_squared, default_config_loop, RadiusHashSearch -from yag_slam_cpp import Wrapper, ScanMatcherConfig, LocalizedRangeScan, Pose2, create_occupancy_grid +from karto_scanmatcher import Wrapper, ScanMatcherConfig, LocalizedRangeScan, Pose2, create_occupancy_grid from yag_slam.scan_matching import Scan2DMatcherCpp from uuid import uuid4 from tiny_tf.tf import Transform diff --git a/yag_slam/helpers.py b/yag_slam/helpers.py index aa45fc0..246d236 100644 --- a/yag_slam/helpers.py +++ b/yag_slam/helpers.py @@ -17,7 +17,7 @@ import time from numba import njit, prange import numpy as np -from yag_slam_cpp import ScanMatcherConfig +from karto_scanmatcher import ScanMatcherConfig from collections import namedtuple diff --git a/yag_slam/models.py b/yag_slam/models.py index ed41393..7ebdc30 100644 --- a/yag_slam/models.py +++ b/yag_slam/models.py @@ -13,9 +13,9 @@ # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . -from yag_slam_cpp import LocalizedRangeScan as LocalizedRangeScanCpp -from yag_slam_cpp import Pose2 as Pose2Cpp -from yag_slam_cpp import LaserScanConfig +from karto_scanmatcher import LocalizedRangeScan as LocalizedRangeScanCpp +from karto_scanmatcher import Pose2 as Pose2Cpp +from karto_scanmatcher import LaserScanConfig from tiny_tf.tf import Transform import numpy as np from yag_slam.helpers import _get_point_readings diff --git a/yag_slam/scan_matching.py b/yag_slam/scan_matching.py index 657d294..fc1b78d 100644 --- a/yag_slam/scan_matching.py +++ b/yag_slam/scan_matching.py @@ -19,7 +19,7 @@ import cv2 import time from collections import defaultdict, namedtuple -from yag_slam_cpp import Wrapper, LaserScanConfig +from karto_scanmatcher import Wrapper, LaserScanConfig from yag_slam.helpers import make_config, default_config, default_config_loop from yag_slam.helpers import (_get_point_readings, _project_2d_scan, _rotate_points, calculate_kernel, validate_points, diff --git a/yag_slam/serde.py b/yag_slam/serde.py index 81a9715..cd42070 100644 --- a/yag_slam/serde.py +++ b/yag_slam/serde.py @@ -16,7 +16,7 @@ from collections import namedtuple import json from yag_slam.helpers import make_config -from yag_slam_cpp import ScanMatcherConfig, Pose2, LaserScanConfig, Wrapper +from karto_scanmatcher import ScanMatcherConfig, Pose2, LaserScanConfig, Wrapper from yag_slam.models import LocalizedRangeScan from yag_slam.graph import LinkLabel from tiny_tf.tf import Transform