Initial import.

This commit is contained in:
Kyle Isom 2019-08-03 02:03:44 +00:00
commit 2ecc14f46c
7 changed files with 523 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/build/
/cmake-build-*/
/stage/
/package/

67
CMakeLists.txt Normal file
View File

@ -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)

18
CMakePack.txt Normal file
View File

@ -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)

19
LICENSE.txt Normal file
View File

@ -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.

180
include/wrnav/geom/vector.h Normal file
View File

@ -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

39
include/wrnav/util/math.h Normal file
View File

@ -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

196
test/vector_test.cc Normal file
View File

@ -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();
}