Major updates, start orientation, start documentation.
This commit is contained in:
parent
2ecc14f46c
commit
0dc47cdbce
|
@ -2,3 +2,5 @@
|
|||
/cmake-build-*/
|
||||
/stage/
|
||||
/package/
|
||||
/docs/html/
|
||||
/docs/latex/
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "tools/googletest"]
|
||||
path = extern/googletest
|
||||
url = https://github.com/google/googletest
|
|
@ -4,7 +4,7 @@ cmake_policy(SET CMP0048 NEW)
|
|||
|
||||
## CONFIG
|
||||
|
||||
project(wrnav VERSION 0.0.1 LANGUAGES CXX)
|
||||
project(wrmath VERSION 0.0.1 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
@ -16,14 +16,15 @@ add_compile_options(-fprofile-arcs -ftest-coverage)
|
|||
add_link_options(-fprofile-arcs -ftest-coverage)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(GTEST REQUIRED gtest_main)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
file(GLOB_RECURSE ${PROJECT_NAME}_HEADERS include/**.h)
|
||||
file(GLOB_RECURSE ${PROJECT_NAME}_SOURCES src/*.cc)
|
||||
|
||||
## BUILD
|
||||
|
||||
add_library(lib${PROJECT_NAME} ${${PROJECT_NAME}_SOURCES})
|
||||
# add_library(LIBNAME
|
||||
# SOURCES
|
||||
# )
|
||||
|
@ -44,11 +45,23 @@ install(DIRECTORY include/${PROJECT_NAME}
|
|||
|
||||
# From Modern CMake:
|
||||
# https://cliutils.gitlab.io/modern-cmake/chapters/testing/googletest.html
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/extern/googletest" "extern/googletest")
|
||||
include_directories("${gtest_SOURCE_DIR}/include")
|
||||
mark_as_advanced(
|
||||
BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS
|
||||
gmock_build_tests gtest_build_samples gtest_build_tests
|
||||
gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols
|
||||
)
|
||||
set_target_properties(gtest PROPERTIES FOLDER extern)
|
||||
set_target_properties(gtest_main PROPERTIES FOLDER extern)
|
||||
set_target_properties(gmock PROPERTIES FOLDER extern)
|
||||
set_target_properties(gmock_main PROPERTIES FOLDER extern)
|
||||
|
||||
include(CTest)
|
||||
set(TEST_EXECS)
|
||||
macro(package_add_gtest TESTNAME)
|
||||
add_executable(${TESTNAME} ${ARGN})
|
||||
target_link_libraries(${TESTNAME} ${GTEST_LDFLAGS})
|
||||
target_link_libraries(${TESTNAME} gtest_main lib${PROJECT_NAME})
|
||||
target_compile_options(${TESTNAME} PUBLIC ${GTEST_CFLAGS})
|
||||
add_test(NAME ${TESTNAME} COMMAND ${TESTNAME})
|
||||
set_target_properties(${TESTNAME} PROPERTIES
|
||||
|
@ -57,7 +70,9 @@ macro(package_add_gtest TESTNAME)
|
|||
list(APPEND TEST_EXECS ${TESTNAME})
|
||||
endmacro()
|
||||
|
||||
# define the tests
|
||||
package_add_gtest(vector_test test/vector_test.cc)
|
||||
package_add_gtest(orientation_test test/orientation_test.cc)
|
||||
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose DEPENDS ${TEST_EXECS})
|
||||
|
||||
|
@ -65,3 +80,7 @@ add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose DEPENDS ${TEST_
|
|||
## DEPLOY
|
||||
|
||||
include(CMakePack.txt)
|
||||
|
||||
|
||||
## DOCUMENTATE
|
||||
add_subdirectory ("docs")
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
find_package(Doxygen REQUIRED)
|
||||
|
||||
# Find all the public headers
|
||||
get_target_property(WRMATH_PUBLIC_HEADER_DIR libwrmath INTERFACE_INCLUDE_DIRECTORIES)
|
||||
file(GLOB_RECURSE WRMATH_PUBLIC_HEADERS ${WRMATH_PUBLIC_HEADER_DIR}/*.h)
|
||||
|
||||
#This will be the main output of our command
|
||||
set(DOXYGEN_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/html/index.html)
|
||||
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
DEPENDS ${WRMATH_PUBLIC_HEADERS}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY Doxyfile
|
||||
COMMENT "Generating docs")
|
||||
|
||||
add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
sphinx
|
||||
breathe
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 4e29e48840e611ecbef33d10960d7480d2e9034a
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __WRMATH_GEOM_H
|
||||
#define __WRMATH_GEOM_H
|
||||
|
||||
#include <wrmath/geom/vector.h>
|
||||
#include <wrmath/geom/orientation.h>
|
||||
|
||||
#endif // __WRMATH_GEOM_H
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Created by kyle on 8/3/19.
|
||||
//
|
||||
|
||||
#ifndef __WRMATH_GEOM_ORIENTATION_H
|
||||
#define __WRMATH_GEOM_ORIENTATION_H
|
||||
|
||||
|
||||
#include <wrmath/geom/vector.h>
|
||||
|
||||
|
||||
namespace wr {
|
||||
namespace geom {
|
||||
|
||||
|
||||
float RadiansToDegreesF(float rads);
|
||||
double RadiansToDegreesD(double rads);
|
||||
float DegreesToRadiansF(float degrees);
|
||||
double DegreesToRadiansD(double degrees);
|
||||
|
||||
|
||||
constexpr uint8_t Basis_i = 0;
|
||||
constexpr uint8_t Basis_j = 1;
|
||||
constexpr uint8_t Basis_k = 2;
|
||||
|
||||
|
||||
static const Vector2d Basis2d[] = {
|
||||
Vector2d{1, 0},
|
||||
Vector2d{0, 1},
|
||||
};
|
||||
|
||||
|
||||
static const Vector2f Basis2f[] = {
|
||||
Vector2f{1, 0},
|
||||
Vector2f{0, 1},
|
||||
};
|
||||
|
||||
|
||||
static const Vector3d Basis3d[] = {
|
||||
Vector3d{1, 0, 0},
|
||||
Vector3d{0, 1, 0},
|
||||
Vector3d{0, 0, 1},
|
||||
};
|
||||
|
||||
|
||||
static const Vector3f Basis3f[] = {
|
||||
Vector3f{1, 0, 0},
|
||||
Vector3f{0, 1, 0},
|
||||
Vector3f{0, 0, 1},
|
||||
};
|
||||
|
||||
|
||||
|
||||
float Heading2f(Vector2f vec);
|
||||
double Heading2d(Vector2d vec);
|
||||
float Heading3f(Vector3f vec);
|
||||
double Heading3d(Vector3d vec);
|
||||
|
||||
} // namespace geom
|
||||
} // namespace wr
|
||||
|
||||
|
||||
#endif // __WRMATH_ORIENTATION_H
|
|
@ -0,0 +1,363 @@
|
|||
#ifndef __WRMATH_GEOM_VECTOR_H
|
||||
#define __WRMATH_GEOM_VECTOR_H
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
#include <wrmath/util/math.h>
|
||||
|
||||
|
||||
namespace wr {
|
||||
namespace geom {
|
||||
|
||||
/**
|
||||
* Vector provides a standard interface for dimensionless fixed-size
|
||||
* vectors. Once instantiated, they cannot be modified. Note that while
|
||||
* the type is generic, it's intended to be used with floating-point
|
||||
* types. They can be indexed like arrays, and they contain an epsilon
|
||||
* value that defines a tolerance for equality.
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
class Vector {
|
||||
public:
|
||||
/**
|
||||
* The default constructor creates a zero vector for a given
|
||||
* type and size.
|
||||
*/
|
||||
Vector() { wr::util::DefaultEpsilon(this->epsilon); }
|
||||
|
||||
/**
|
||||
* If given an initializer_list, the vector is created with
|
||||
* those values. There must be exactly N elements in the list.
|
||||
* @param ilst
|
||||
*/
|
||||
Vector(std::initializer_list<T> ilst)
|
||||
{
|
||||
assert(ilst.size() == N);
|
||||
|
||||
wr::util::DefaultEpsilon(this->epsilon);
|
||||
std::copy(ilst.begin(), ilst.end(), this->arr.begin());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Magnitude computes the length of the vector.
|
||||
* @return The length of the vector.
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the tolerance for equality checks. At a minimum, this allows
|
||||
* for systemic errors in floating math arithmetic.
|
||||
*
|
||||
* @param eps is the maximum difference between this vector and
|
||||
* another.
|
||||
*/
|
||||
void
|
||||
setEpsilon(T eps)
|
||||
{
|
||||
this->epsilon = eps;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether this is a zero vector.
|
||||
* @return true if the vector is zero.
|
||||
*/
|
||||
bool
|
||||
isZero() const
|
||||
{
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (!wr::util::WithinTolerance(this->arr[i], (T)0.0, this->epsilon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the unit vector for this vector.
|
||||
* @return The unit vector
|
||||
*/
|
||||
Vector
|
||||
unitVector() const
|
||||
{
|
||||
return *this / this->magnitude();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if this is a unit vector, e.g. if its length is 1.
|
||||
* @return true if the vector is a unit vector.
|
||||
*/
|
||||
bool
|
||||
isUnitVector() const
|
||||
{
|
||||
return wr::util::WithinTolerance(this->magnitude(), (T)1.0, this->epsilon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute the angle between two other vectors.
|
||||
* @param other Another vector.
|
||||
* @return The angle in radians between the two vectors.
|
||||
*/
|
||||
T
|
||||
angle(const Vector<T, N> &other) const
|
||||
{
|
||||
Vector<T, N> unitA = this->unitVector();
|
||||
Vector<T, N> unitB = other.unitVector();
|
||||
|
||||
// Can't compute angles with a zero vector.
|
||||
assert(!this->isZero());
|
||||
assert(!other.isZero());
|
||||
return std::acos(unitA * unitB);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether two vectors are parallel.
|
||||
* @param other Another vector
|
||||
* @return True if the angle between the vectors is zero.
|
||||
*/
|
||||
bool
|
||||
isParallel(const Vector<T, N> &other) const
|
||||
{
|
||||
if (this->isZero() || other.isZero()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
T angle = this->angle(other);
|
||||
if (wr::util::WithinTolerance(angle, (T)0.0, this->epsilon)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two vectors are orthogonal or perpendicular to each
|
||||
* other.
|
||||
* @param other Another vector
|
||||
* @return True if the two vectors are orthogonal.
|
||||
*/
|
||||
bool
|
||||
isOrthogonal(const Vector<T, N> &other) const
|
||||
{
|
||||
if (this->isZero() || other.isZero()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return wr::util::WithinTolerance(*this * other, (T)0.0, this->epsilon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Project this vector onto some basis vector.
|
||||
* @param basis The basis vector to be projected onto.
|
||||
* @return A vector that is the projection of this onto the basis
|
||||
* vector.
|
||||
*/
|
||||
Vector
|
||||
projectParallel(const Vector<T, N> &basis) const
|
||||
{
|
||||
Vector<T, N> unit_basis = basis.unitVector();
|
||||
|
||||
return unit_basis * (*this * unit_basis);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Project this vector perpendicularly onto some basis vector.
|
||||
* This is also called the rejection of the vector.
|
||||
* @param basis The basis vector to be projected onto.
|
||||
* @return A vector that is the orthogonal projection of this onto
|
||||
* the basis vector.
|
||||
*/
|
||||
Vector
|
||||
projectOrthogonal(const Vector<T, N> &basis)
|
||||
{
|
||||
Vector<T, N> spar = this->projectParallel(basis);
|
||||
return *this - spar;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform vector addition with another vector.
|
||||
* @param other The vector to be added.
|
||||
* @return A new vector that is the result of adding this and the
|
||||
* other vector.
|
||||
*/
|
||||
Vector operator+(const Vector<T, N> &other) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] + other.arr[i];
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform vector subtraction with another vector.
|
||||
* @param other The vector to be subtracted from this vector.
|
||||
* @return A new vector that is the result of subtracting the
|
||||
* other vector from this one.
|
||||
*/
|
||||
Vector operator-(const Vector<T, N> &other) const {
|
||||
Vector<T, N> vec;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
vec.arr[i] = this->arr[i] - other.arr[i];
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform scalar multiplication of this vector by some scale factor.
|
||||
* @param k The scaling value.
|
||||
* @return A new vector that is this vector scaled by k.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform scalar division of this vector by some scale factor.
|
||||
* @param k The scaling value
|
||||
* @return A new vector that is this vector scaled by 1/k.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute the dot product between two vectors.
|
||||
* @param other The other vector.
|
||||
* @return A scalar value that is the dot product of the two vectors.
|
||||
*/
|
||||
T operator*(const Vector<T, N> &other) const {
|
||||
T result = 0;
|
||||
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
result += (this->arr[i] * other.arr[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two vectors for equality.
|
||||
* @param other The other vector.
|
||||
* @return Return true if all the components of both vectors are
|
||||
* within the tolerance value.
|
||||
*/
|
||||
bool operator==(const Vector<T, N> &other) const {
|
||||
for (size_t i = 0; i<N; i++) {
|
||||
if (!wr::util::WithinTolerance(this->arr[i], other.arr[i], this->epsilon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two vectors for inequality.
|
||||
* @param other The other vector.
|
||||
* @return Return true if any of the components of both vectors are
|
||||
* not within the tolerance value.
|
||||
*/
|
||||
bool operator!=(const Vector<T, N> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Support array indexing into vector.
|
||||
* @param i The component index.
|
||||
* @return The value of the vector component at i.
|
||||
*/
|
||||
T operator[](size_t i) const {
|
||||
return this->arr[i];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Support outputting vectors in the form "<i, j, ...>".
|
||||
* @param outs An output stream.
|
||||
* @param vec The vector to be formatted.
|
||||
* @return The output stream.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A number of shorthand aliases for vectors are provided. They follow
|
||||
* the form of VectorNt, where N is the dimension and t is the type.
|
||||
* For example, a 2D float vector is Vector2f.
|
||||
*/
|
||||
|
||||
typedef Vector<float, 2> Vector2f;
|
||||
typedef Vector<float, 3> Vector3f;
|
||||
typedef Vector<float, 4> Vector4f;
|
||||
|
||||
typedef Vector<double, 2> Vector2d;
|
||||
typedef Vector<double, 3> Vector3d;
|
||||
typedef Vector<double, 4> Vector4d;
|
||||
|
||||
|
||||
} // namespace geom
|
||||
} // namespace wr
|
||||
|
||||
|
||||
#endif // __WRMATH_GEOM_VECTOR_H
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef __WRNAV_UTIL_MATH_H
|
||||
#define __WRNAV_UTIL_MATH_H
|
||||
#ifndef __WRMATH_UTIL_MATH_H
|
||||
#define __WRMATH_UTIL_MATH_H
|
||||
|
||||
|
||||
namespace wr {
|
||||
|
@ -10,14 +10,14 @@ const double Epsilon_double = 0.0001;
|
|||
const float Epsilon_float = 0.0001;
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
DefaultEpsilon(double &epsilon)
|
||||
{
|
||||
epsilon = Epsilon_double;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
DefaultEpsilon(float &epsilon)
|
||||
{
|
||||
epsilon = Epsilon_float;
|
||||
|
@ -25,7 +25,7 @@ DefaultEpsilon(float &epsilon)
|
|||
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
static T
|
||||
WithinTolerance(T a, T b, T epsilon)
|
||||
{
|
||||
return std::abs(a - b) < epsilon;
|
||||
|
@ -36,4 +36,4 @@ WithinTolerance(T a, T b, T epsilon)
|
|||
} // namespace wr
|
||||
|
||||
|
||||
#endif // __WRNAV_UTIL_MATH_H
|
||||
#endif // __WRMATH_UTIL_MATH_H
|
|
@ -1,180 +0,0 @@
|
|||
#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,68 @@
|
|||
#include <cmath>
|
||||
#include <wrmath/geom/orientation.h>
|
||||
|
||||
|
||||
namespace wr {
|
||||
namespace geom {
|
||||
|
||||
|
||||
float
|
||||
RadiansToDegreesF(float rads)
|
||||
{
|
||||
return rads * (180.0 / M_PI);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
RadiansToDegreesD(double rads)
|
||||
{
|
||||
return rads * (180.0 / M_PI);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
DegreesToRadiansF(float degrees)
|
||||
{
|
||||
return degrees * M_PI / 180.0;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
DegreesToRadiansD(double degrees)
|
||||
{return degrees * M_PI / 180.0;
|
||||
return degrees * M_PI / 180.0;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
Heading2f(Vector2f vec)
|
||||
{
|
||||
return vec.angle(Basis2f[Basis_i]);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
Heading3f(Vector3f vec)
|
||||
{
|
||||
Vector2f vec2f {vec[0], vec[1]};
|
||||
return Heading2f(vec2f);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
Heading2d(Vector2d vec)
|
||||
{
|
||||
return vec.angle(Basis2d[Basis_i]);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
Heading3d(Vector3d vec)
|
||||
{
|
||||
Vector2d vec2d {vec[0], vec[1]};
|
||||
return Heading2d(vec2d);
|
||||
}
|
||||
|
||||
|
||||
} // namespace geom
|
||||
} // namespace wr
|
|
@ -0,0 +1,46 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <wrmath/geom/vector.h>
|
||||
#include <wrmath/geom/orientation.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace wr;
|
||||
|
||||
|
||||
TEST(Orientation2f, Heading)
|
||||
{
|
||||
geom::Vector2f a {2.0, 2.0};
|
||||
|
||||
EXPECT_FLOAT_EQ(geom::Heading2f(a), geom::DegreesToRadiansF(45));
|
||||
}
|
||||
|
||||
|
||||
TEST(Orientation3f, Heading)
|
||||
{
|
||||
geom::Vector3f a {2.0, 2.0, 2.0};
|
||||
|
||||
EXPECT_FLOAT_EQ(geom::Heading3f(a), geom::DegreesToRadiansF(45));
|
||||
}
|
||||
|
||||
|
||||
TEST(Orientation2d, Heading)
|
||||
{
|
||||
geom::Vector2d a {2.0, 2.0};
|
||||
|
||||
EXPECT_NEAR(geom::Heading2d(a), geom::DegreesToRadiansF(45), 0.000001);
|
||||
}
|
||||
|
||||
|
||||
TEST(Orientation3d, Heading)
|
||||
{
|
||||
geom::Vector3d a {2.0, 2.0, 2.0};
|
||||
|
||||
EXPECT_NEAR(geom::Heading3d(a), geom::DegreesToRadiansF(45), 0.000001);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <wrnav/geom/vector.h>
|
||||
#include <wrmath/geom/vector.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace wr;
|
||||
|
@ -82,6 +81,8 @@ TEST(Vector3FloatTests, UnitVector)
|
|||
geom::Vector3f unit {0.6651669556972103, 0.7069150218815566, 0.24046636539587804};
|
||||
|
||||
EXPECT_EQ(vec3.unitVector(), unit);
|
||||
EXPECT_FALSE(vec3.isUnitVector());
|
||||
EXPECT_TRUE(unit.isUnitVector());
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,6 +97,37 @@ TEST(Vector3FloatTests, Angle)
|
|||
EXPECT_NEAR(c.angle(d), 1.052, 0.001);
|
||||
}
|
||||
|
||||
TEST(Vector3FloatTests, ParallelOrthogonalVectors)
|
||||
{
|
||||
geom::Vector3f a {-2.029, 9.97, 4.172};
|
||||
geom::Vector3f b {-9.231, -6.639, -7.245};
|
||||
geom::Vector3f c {-2.328, -7.284, -1.214};
|
||||
geom::Vector3f d {-1.821, 1.072, -2.94};
|
||||
geom::Vector3f e {-2.0, 1.0, 3.0};
|
||||
geom::Vector3f f {-6.0, 3.0, 9.0};
|
||||
|
||||
EXPECT_FALSE(a.isParallel(b));
|
||||
EXPECT_FALSE(a.isOrthogonal(b));
|
||||
|
||||
EXPECT_FALSE(c.isParallel(d));
|
||||
EXPECT_TRUE(c.isOrthogonal(d));
|
||||
|
||||
EXPECT_TRUE(e.isParallel(f));
|
||||
EXPECT_FALSE(e.isOrthogonal(f));
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3FloatTests, Projections)
|
||||
{
|
||||
geom::Vector4f a {3.009, -6.172, 3.692, -2.510};
|
||||
geom::Vector4f b {6.404, -9.144, 2.759, 8.718};
|
||||
geom::Vector4f c {1.9685, -2.8108, 0.8481, 2.6798};
|
||||
geom::Vector4f d {1.0405, -3.3612, 2.8439, -5.1898};
|
||||
|
||||
ASSERT_EQ(a.projectParallel(b), c);
|
||||
ASSERT_EQ(a.projectOrthogonal(b), d);
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Magnitude)
|
||||
{
|
||||
|
@ -173,6 +205,8 @@ TEST(Vector3DoubleTests, UnitVector)
|
|||
geom::Vector3d unit {0.6651669556972103, 0.7069150218815566, 0.24046636539587804};
|
||||
|
||||
EXPECT_EQ(vec3.unitVector(), unit);
|
||||
EXPECT_FALSE(vec3.isUnitVector());
|
||||
EXPECT_TRUE(unit.isUnitVector());
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,6 +222,38 @@ TEST(Vector3DoubleTests, Angle)
|
|||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, ParallelOrthogonalVectors)
|
||||
{
|
||||
geom::Vector3d a {-2.029, 9.97, 4.172};
|
||||
geom::Vector3d b {-9.231, -6.639, -7.245};
|
||||
geom::Vector3d c {-2.328, -7.284, -1.214};
|
||||
geom::Vector3d d {-1.821, 1.072, -2.94};
|
||||
geom::Vector3d e {-2.0, 1.0, 3.0};
|
||||
geom::Vector3d f {-6.0, 3.0, 9.0};
|
||||
|
||||
EXPECT_FALSE(a.isParallel(b));
|
||||
EXPECT_FALSE(a.isOrthogonal(b));
|
||||
|
||||
EXPECT_FALSE(c.isParallel(d));
|
||||
EXPECT_TRUE(c.isOrthogonal(d));
|
||||
|
||||
EXPECT_TRUE(e.isParallel(f));
|
||||
EXPECT_FALSE(e.isOrthogonal(f));
|
||||
}
|
||||
|
||||
|
||||
TEST(Vector3DoubleTests, Projections)
|
||||
{
|
||||
geom::Vector4d a {3.009, -6.172, 3.692, -2.510};
|
||||
geom::Vector4d b {6.404, -9.144, 2.759, 8.718};
|
||||
geom::Vector4d c {1.9685, -2.8108, 0.8481, 2.6798};
|
||||
geom::Vector4d d {1.0405, -3.3612, 2.8439, -5.1898};
|
||||
|
||||
ASSERT_EQ(a.projectParallel(b), c);
|
||||
ASSERT_EQ(a.projectOrthogonal(b), d);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue