Initial import.
This commit is contained in:
commit
2ecc14f46c
|
@ -0,0 +1,4 @@
|
|||
/build/
|
||||
/cmake-build-*/
|
||||
/stage/
|
||||
/package/
|
|
@ -0,0 +1,67 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
|
||||
|
||||
## CONFIG
|
||||
|
||||
project(wrnav VERSION 0.0.1 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_compile_options(-Werror -Wall -g -O0)
|
||||
|
||||
if(DEFINED ENV{CMAKE_GCOV})
|
||||
add_compile_options(-fprofile-arcs -ftest-coverage)
|
||||
# Need CMake 3.15+.
|
||||
add_link_options(-fprofile-arcs -ftest-coverage)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(GTEST REQUIRED gtest_main)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
|
||||
## BUILD
|
||||
|
||||
# add_library(LIBNAME
|
||||
# SOURCES
|
||||
# )
|
||||
#
|
||||
# add_executable(EXE_NAME MAIN)
|
||||
# target_link_libraries(EXE_NAME LIBNAMES)
|
||||
# add_dependencies(EXE_NAME LIBNAMES)
|
||||
|
||||
|
||||
## INSTALL
|
||||
|
||||
install(DIRECTORY include/${PROJECT_NAME}
|
||||
DESTINATION include/
|
||||
FILES_MATCHING PATTERN "*.h")
|
||||
|
||||
|
||||
## TEST
|
||||
|
||||
# From Modern CMake:
|
||||
# https://cliutils.gitlab.io/modern-cmake/chapters/testing/googletest.html
|
||||
include(CTest)
|
||||
set(TEST_EXECS)
|
||||
macro(package_add_gtest TESTNAME)
|
||||
add_executable(${TESTNAME} ${ARGN})
|
||||
target_link_libraries(${TESTNAME} ${GTEST_LDFLAGS})
|
||||
target_compile_options(${TESTNAME} PUBLIC ${GTEST_CFLAGS})
|
||||
add_test(NAME ${TESTNAME} COMMAND ${TESTNAME})
|
||||
set_target_properties(${TESTNAME} PROPERTIES
|
||||
FOLDER tests
|
||||
RUNTIME_OUTPUT_DIRECTORY tests)
|
||||
list(APPEND TEST_EXECS ${TESTNAME})
|
||||
endmacro()
|
||||
|
||||
package_add_gtest(vector_test test/vector_test.cc)
|
||||
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose DEPENDS ${TEST_EXECS})
|
||||
|
||||
|
||||
## DEPLOY
|
||||
|
||||
include(CMakePack.txt)
|
|
@ -0,0 +1,18 @@
|
|||
# build a CPack driven installer package
|
||||
include(InstallRequiredSystemLibraries)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${${PROJECT_NAME}_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${${PROJECT_NAME}_VERSION_MINOR}")
|
||||
|
||||
# Debian settings
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "K. Isom")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Shimmering Clarity C++ library")
|
||||
set(CPACK_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION})
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc++1 (>= 3.7.0-1)")
|
||||
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION devel)
|
||||
|
||||
# actually do the thing
|
||||
set(CPACK_GENERATOR DEB)
|
||||
include (CPack)
|
|
@ -0,0 +1,19 @@
|
|||
Copyright 2019 Kyle Isom <kyle@imap.cc>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,180 @@
|
|||
#ifndef __WRNAV_GEOM_VECTOR_H
|
||||
#define __WRNAV_GEOM_VECTOR_H
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
#include <wrnav/util/math.h>
|
||||
|
||||
|
||||
namespace wr {
|
||||
namespace geom {
|
||||
|
||||
template <typename T, size_t N>
|
||||
class Vector {
|
||||
public:
|
||||
Vector() { wr::util::DefaultEpsilon(this->epsilon); }
|
||||
|
||||
Vector(std::initializer_list<T> ilst)
|
||||
{
|
||||
assert(ilst.size() == N);
|
||||
|
||||
wr::util::DefaultEpsilon(this->epsilon);
|
||||
std::copy(ilst.begin(), ilst.end(), this->arr.begin());
|
||||
}
|
||||
|
||||
|
||||
T magnitude() const {
|
||||
T result = 0;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
result += (this->arr[i] * this->arr[i]);
|
||||
}
|
||||
return std::sqrt(result);
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
setEpsilon(T epsilon)
|
||||
{
|
||||
this->epsilon = epsilon;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
isZero() const
|
||||
{
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (!wr::util::WithinTolerance(this->arr[i], 0.0, this->epsilon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Vector
|
||||
unitVector() const
|
||||
{
|
||||
return *this / this->magnitude();
|
||||
}
|
||||
|
||||
|
||||
T
|
||||
angle(const Vector<T, N> &rhs) const
|
||||
{
|
||||
Vector<T, N> unitA = this->unitVector();
|
||||
Vector<T, N> unitB = rhs.unitVector();
|
||||
|
||||
return std::acos(unitA * unitB);
|
||||
}
|
||||
|
||||
|
||||
Vector operator+(const Vector<T, N> &rhs) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] + rhs.arr[i];
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
Vector operator-(const Vector<T, N> &rhs) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] - rhs.arr[i];
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
// Scalar multiplication.
|
||||
Vector operator*(const T k) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] * k;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
// Scalar division.
|
||||
Vector operator/(const T k) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] / k;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
// Dot product.
|
||||
T operator*(const Vector<T, N> &rhs) const {
|
||||
T result = 0;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
result += (this->arr[i] * rhs.arr[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const Vector<T, N> &rhs) const {
|
||||
for (size_t i = 0; i<N; i++) {
|
||||
if (!wr::util::WithinTolerance(this->arr[i], rhs.arr[i], this->epsilon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(const Vector<T, N> &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& outs, const Vector<T, N>& vec) {
|
||||
outs << "<";
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
outs << vec.arr[i];
|
||||
if (i < (N-1)) {
|
||||
outs << ", ";
|
||||
}
|
||||
}
|
||||
outs << ">";
|
||||
return outs;
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t dim = N;
|
||||
T epsilon;
|
||||
std::array<T, N> arr;
|
||||
};
|
||||
|
||||
|
||||
typedef Vector<float, 3> Vector3f;
|
||||
typedef Vector<float, 4> Vector4f;
|
||||
typedef Vector<double, 3> Vector3d;
|
||||
typedef Vector<double, 4> Vector4d;
|
||||
|
||||
|
||||
} // namespace geom
|
||||
} // namespace wr
|
||||
|
||||
|
||||
#endif // __WRNAV_GEOM_VECTOR_H
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef __WRNAV_UTIL_MATH_H
|
||||
#define __WRNAV_UTIL_MATH_H
|
||||
|
||||
|
||||
namespace wr {
|
||||
namespace util {
|
||||
|
||||
|
||||
const double Epsilon_double = 0.0001;
|
||||
const float Epsilon_float = 0.0001;
|
||||
|
||||
|
||||
void
|
||||
DefaultEpsilon(double &epsilon)
|
||||
{
|
||||
epsilon = Epsilon_double;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DefaultEpsilon(float &epsilon)
|
||||
{
|
||||
epsilon = Epsilon_float;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
WithinTolerance(T a, T b, T epsilon)
|
||||
{
|
||||
return std::abs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
|
||||
} // namespace util
|
||||
} // namespace wr
|
||||
|
||||
|
||||
#endif // __WRNAV_UTIL_MATH_H
|
|
@ -0,0 +1,196 @@
|
|||
#include <iostream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <wrnav/geom/vector.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace wr;
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Magnitude)
|
||||
{
|
||||
geom::Vector3f v3f {1.0, -2.0, 3.0};
|
||||
const float expected = 3.74165738677394;
|
||||
|
||||
EXPECT_FLOAT_EQ(v3f.magnitude(), expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Equality)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f b {1.0, 2.0, 3.0};
|
||||
geom::Vector3f c {1.0, 2.0, 1.0};
|
||||
|
||||
EXPECT_EQ(a, b);
|
||||
EXPECT_EQ(b, a);
|
||||
EXPECT_NE(a, c);
|
||||
EXPECT_NE(b, c);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Addition)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f b {4.0, 5.0, 6.0};
|
||||
geom::Vector3f expected {5.0, 7.0, 9.0};
|
||||
|
||||
EXPECT_EQ(a+b, expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Subtraction)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f b {4.0, 5.0, 6.0};
|
||||
geom::Vector3f c {5.0, 7.0, 9.0};
|
||||
|
||||
EXPECT_EQ(c-b, a);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, ScalarMultiplication)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f expected {3.0, 6.0, 9.0};
|
||||
|
||||
EXPECT_EQ(a * 3.0, expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, ScalarDivision)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f b {3.0, 6.0, 9.0};
|
||||
|
||||
EXPECT_EQ(b / 3.0, a);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, DotProduct)
|
||||
{
|
||||
geom::Vector3f a {1.0, 2.0, 3.0};
|
||||
geom::Vector3f b {4.0, 5.0, 6.0};
|
||||
|
||||
EXPECT_FLOAT_EQ(a * b, 32.0);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, UnitVector)
|
||||
{
|
||||
// Test values randomly generated and calculated with numpy.
|
||||
geom::Vector3f vec3 {5.320264018493507, 5.6541812891273935, 1.9233435162644652};
|
||||
geom::Vector3f unit {0.6651669556972103, 0.7069150218815566, 0.24046636539587804};
|
||||
|
||||
EXPECT_EQ(vec3.unitVector(), unit);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Angle)
|
||||
{
|
||||
geom::Vector3f a {0.3977933061361172, 8.053980094436525, 8.1287759943773};
|
||||
geom::Vector3f b {9.817895298608196, 4.034166890407462, 4.37628316513266};
|
||||
geom::Vector3f c {7.35, 0.221, 5.188};
|
||||
geom::Vector3f d {2.751, 8.259, 3.985};
|
||||
|
||||
EXPECT_FLOAT_EQ(a.angle(b), 0.9914540426033251);
|
||||
EXPECT_NEAR(c.angle(d), 1.052, 0.001);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Magnitude)
|
||||
{
|
||||
geom::Vector3d v3d{1.0, -2.0, 3.0};
|
||||
const double expected = 3.74165738677394;
|
||||
|
||||
EXPECT_DOUBLE_EQ(v3d.magnitude(), expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Equality)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d b {1.0, 2.0, 3.0};
|
||||
geom::Vector3d c {1.0, 2.0, 1.0};
|
||||
|
||||
EXPECT_EQ(a, b);
|
||||
EXPECT_EQ(b, a);
|
||||
EXPECT_NE(a, c);
|
||||
EXPECT_NE(b, c);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Addition)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d b {4.0, 5.0, 6.0};
|
||||
geom::Vector3d expected {5.0, 7.0, 9.0};
|
||||
|
||||
EXPECT_EQ(a+b, expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Subtraction)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d b {4.0, 5.0, 6.0};
|
||||
geom::Vector3d c {5.0, 7.0, 9.0};
|
||||
|
||||
EXPECT_EQ(c-b, a);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, ScalarMultiplication)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d expected {3.0, 6.0, 9.0};
|
||||
|
||||
EXPECT_EQ(a * 3.0, expected);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, ScalarDivision)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d b {3.0, 6.0, 9.0};
|
||||
|
||||
EXPECT_EQ(b / 3.0, a);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, DotProduct)
|
||||
{
|
||||
geom::Vector3d a {1.0, 2.0, 3.0};
|
||||
geom::Vector3d b {4.0, 5.0, 6.0};
|
||||
|
||||
EXPECT_DOUBLE_EQ(a * b, 32.0);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, UnitVector)
|
||||
{
|
||||
// Test values randomly generated and calculated with numpy.
|
||||
geom::Vector3d vec3 {5.320264018493507, 5.6541812891273935, 1.9233435162644652};
|
||||
geom::Vector3d unit {0.6651669556972103, 0.7069150218815566, 0.24046636539587804};
|
||||
|
||||
EXPECT_EQ(vec3.unitVector(), unit);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Angle)
|
||||
{
|
||||
geom::Vector3d a {0.3977933061361172, 8.053980094436525, 8.1287759943773};
|
||||
geom::Vector3d b {9.817895298608196, 4.034166890407462, 4.37628316513266};
|
||||
geom::Vector3d c {7.35, 0.221, 5.188};
|
||||
geom::Vector3d d {2.751, 8.259, 3.985};
|
||||
|
||||
EXPECT_DOUBLE_EQ(a.angle(b), 0.9914540426033251);
|
||||
EXPECT_NEAR(c.angle(d), 1.052, 0.001);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in New Issue