Restructure project, start importing sc3 code.
This commit is contained in:
parent
3122ed6ac7
commit
5f3dc6e9f6
|
@ -33,28 +33,36 @@ endif ()
|
||||||
add_compile_definitions(SCSL_DESKTOP_BUILD)
|
add_compile_definitions(SCSL_DESKTOP_BUILD)
|
||||||
add_compile_definitions(SCSL_VERSION=${PROJECT_VERSION})
|
add_compile_definitions(SCSL_VERSION=${PROJECT_VERSION})
|
||||||
|
|
||||||
set(HEADER_FILES scsl.h
|
set(HEADER_FILES
|
||||||
Arena.h
|
include/scsl/scsl.h
|
||||||
Buffer.h
|
include/scsl/Arena.h
|
||||||
Commander.h
|
include/scsl/Buffer.h
|
||||||
Dictionary.h
|
include/scsl/Commander.h
|
||||||
Exceptions.h
|
include/scsl/Dictionary.h
|
||||||
Flag.h
|
include/scsl/Exceptions.h
|
||||||
StringUtil.h
|
include/scsl/Flag.h
|
||||||
TLV.h
|
include/scsl/StringUtil.h
|
||||||
Test.h
|
include/scsl/TLV.h
|
||||||
|
|
||||||
|
include/sctest/Assert.h
|
||||||
|
include/sctest/Report.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
Arena.cc
|
src/sl/Arena.cc
|
||||||
Buffer.cc
|
src/sl/Buffer.cc
|
||||||
Commander.cc
|
src/sl/Commander.cc
|
||||||
Dictionary.cc
|
src/sl/Dictionary.cc
|
||||||
Exceptions.cc
|
src/sl/Exceptions.cc
|
||||||
Flag.cc
|
src/sl/Flag.cc
|
||||||
StringUtil.cc
|
src/sl/StringUtil.cc
|
||||||
TLV.cc
|
src/sl/TLV.cc
|
||||||
Test.cc
|
|
||||||
|
src/test/Assert.cc
|
||||||
|
src/test/Report.cc
|
||||||
|
src/test/SimpleSuite.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -67,31 +75,27 @@ add_library(scsl
|
||||||
${SOURCE_FILES} ${HEADER_FILES})
|
${SOURCE_FILES} ${HEADER_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(phonebook phonebook.cc)
|
add_executable(phonebook src/bin/phonebook.cc)
|
||||||
target_link_libraries(phonebook scsl)
|
target_link_libraries(phonebook scsl)
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
add_executable(buffer_test bufferTest.cc)
|
set(TEST_SOURCES)
|
||||||
target_link_libraries(buffer_test scsl)
|
macro(generate_test name)
|
||||||
add_test(bufferTest buffer_test)
|
add_executable(test_${name} test/${name}.cc ${TEST_SOURCES} ${ARGN})
|
||||||
|
target_link_libraries(test_${name} ${PROJECT_NAME})
|
||||||
|
target_include_directories(test_${name} PRIVATE test)
|
||||||
|
add_test(test_${name} test_${name})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
add_executable(tlv_test tlvTest.cc)
|
generate_test(buffer)
|
||||||
target_link_libraries(tlv_test scsl)
|
generate_test(tlv)
|
||||||
add_test(tlvTest tlv_test)
|
generate_test(dictionary)
|
||||||
|
generate_test(flag)
|
||||||
|
generate_test(stringutil)
|
||||||
|
|
||||||
add_executable(dictionary_test dictionaryTest.cc)
|
generate_test(simple_suite_example)
|
||||||
target_link_libraries(dictionary_test scsl)
|
|
||||||
add_test(dictionaryTest dictionary_test)
|
|
||||||
|
|
||||||
add_executable(flag_test flagTest.cc)
|
|
||||||
target_link_libraries(flag_test scsl)
|
|
||||||
add_test(flagTest flag_test)
|
|
||||||
|
|
||||||
add_executable(stringutil_test stringutil_test.cc)
|
|
||||||
target_link_libraries(stringutil_test scsl)
|
|
||||||
add_test(stringutilTest stringutil_test)
|
|
||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
write_basic_package_version_file(
|
write_basic_package_version_file(
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/// coord2d.h defines 2D point and polar coordinate systems.
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/math/coord2d.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: math::geom
|
||||||
|
//
|
||||||
|
// coord2d.h defines 2D coordinate classes and functions.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef SCMATH_GEOM_COORD2D_H
|
||||||
|
#define SCMATH_GEOM_COORD2D_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
class Point2D;
|
||||||
|
class Polar2D;
|
||||||
|
|
||||||
|
// Point2D is a logical grouping of a set of 2D cartesian coordinates.
|
||||||
|
class Point2D {
|
||||||
|
public:
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
// A Point2D can be initialised by setting its members to 0, by providing the
|
||||||
|
// x and y coordiantes, or through translation from a polar coordinate.
|
||||||
|
Point2D() : x(0), y(0) {}
|
||||||
|
Point2D(int _x, int _y) : x(_x), y(_y) {}
|
||||||
|
Point2D(const Polar2D&);
|
||||||
|
|
||||||
|
std::string ToString(void);
|
||||||
|
void ToPolar(Polar2D&);
|
||||||
|
|
||||||
|
// Rotate rotates the point by theta radians. Alternatively, a rotation
|
||||||
|
// can use this point as the centre, with a polar coordinate and a rotation
|
||||||
|
// amount (in radians). The latter is used to specify a central point
|
||||||
|
// of rotation with vertices specified as polar coordinates from the centre.
|
||||||
|
// Both forms take a reference to a Point2D to store the rotated point.
|
||||||
|
void Rotate(Point2D& rotated, double theta);
|
||||||
|
std::vector<Point2D> Rotate(std::vector<Polar2D>, double);
|
||||||
|
|
||||||
|
// Translate adds this point to the first argument, storing the result in the
|
||||||
|
// second argument.
|
||||||
|
void Translate(const Point2D& other, Point2D& translated);
|
||||||
|
|
||||||
|
// Distance returns the distance from this point to another.
|
||||||
|
int Distance(const Point2D& other);
|
||||||
|
|
||||||
|
Point2D operator+(const Point2D &rhs) const { return Point2D(x + rhs.x, y + rhs.y); }
|
||||||
|
Point2D operator-(const Point2D &rhs) const { return Point2D(x - rhs.x, y - rhs.y); }
|
||||||
|
Point2D operator*(const int k) const { return Point2D(x * k, y * k); }
|
||||||
|
bool operator==(const Point2D& rhs) const;
|
||||||
|
bool operator!=(const Point2D& rhs) const { return !(*this == rhs); }
|
||||||
|
friend std::ostream& operator<<(std::ostream& outs, const Point2D& pt);
|
||||||
|
};
|
||||||
|
|
||||||
|
// A Polar2D is a 2D polar coordinate, specified in terms of the radius from
|
||||||
|
// some origin and the angle from the positive X axis of a cartesian coordinate
|
||||||
|
// system.
|
||||||
|
class Polar2D {
|
||||||
|
public:
|
||||||
|
double r, theta;
|
||||||
|
|
||||||
|
// A Polar2D can be initialised as a zeroised polar coordinate, by specifying
|
||||||
|
// the radius and angle directly, or via conversion from a Point2D.
|
||||||
|
Polar2D() : r(0.0), theta(0.0) {}
|
||||||
|
Polar2D(double _r, double _theta) : r(_r), theta(_theta) {}
|
||||||
|
Polar2D(const Point2D&);
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
|
void ToPoint(Point2D&);
|
||||||
|
|
||||||
|
// Rotate rotates the polar coordinate by the number of radians, storing the result
|
||||||
|
// in the Polar2D argument.
|
||||||
|
void Rotate(Polar2D&, double);
|
||||||
|
|
||||||
|
// RotateAround rotates this point about by theta radians, storing the rotated point
|
||||||
|
// in result.
|
||||||
|
void RotateAround(const Point2D& other, Point2D& result, double tjeta);
|
||||||
|
|
||||||
|
bool operator==(const Polar2D&) const;
|
||||||
|
bool operator!=(const Polar2D& rhs) const { return !(*this == rhs); }
|
||||||
|
friend std::ostream& operator<<(std::ostream&, const Polar2D&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace geom
|
||||||
|
} // end namespace math
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* orientation.h concerns itself with computing the orientation of some
|
||||||
|
* vector with respect to a reference plane that is assumed to be the
|
||||||
|
* of the Earth.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SCMATH_GEOM_ORIENTATION_H
|
||||||
|
#define SCMATH_GEOM_ORIENTATION_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
/// \defgroup basis Basis vector indices.
|
||||||
|
/// The following constants are provided as a convenience for indexing two-
|
||||||
|
/// and three-dimensional vectors.
|
||||||
|
|
||||||
|
/// \ingroup basis
|
||||||
|
/// Convenience constant for the x index.
|
||||||
|
constexpr uint8_t Basis_x = 0;
|
||||||
|
|
||||||
|
/// \ingroup basis
|
||||||
|
/// Convenience constant for the y index.
|
||||||
|
constexpr uint8_t Basis_y = 1;
|
||||||
|
|
||||||
|
/// \ingroup basis
|
||||||
|
/// Convenience constant for the z index.
|
||||||
|
constexpr uint8_t Basis_z = 2;
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Basis2d provides basis vectors for Vector2ds.
|
||||||
|
static const Vector2d Basis2d[] = {
|
||||||
|
Vector2d{1, 0},
|
||||||
|
Vector2d{0, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Basis2d provides basis vectors for Vector2fs.
|
||||||
|
static const Vector2f Basis2f[] = {
|
||||||
|
Vector2f{1, 0},
|
||||||
|
Vector2f{0, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Basis2d provides basis vectors for Vector3ds.
|
||||||
|
static const Vector3d Basis3d[] = {
|
||||||
|
Vector3d{1, 0, 0},
|
||||||
|
Vector3d{0, 1, 0},
|
||||||
|
Vector3d{0, 0, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Basis2d provides basis vectors for Vector3fs.
|
||||||
|
static const Vector3f Basis3f[] = {
|
||||||
|
Vector3f{1, 0, 0},
|
||||||
|
Vector3f{0, 1, 0},
|
||||||
|
Vector3f{0, 0, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Heading2f returns a compass heading for a Vector2f.
|
||||||
|
/// @param vec A vector orientation.
|
||||||
|
/// @return The compass heading of the vector in radians.
|
||||||
|
float Heading2f(Vector2f vec);
|
||||||
|
|
||||||
|
/// Heading2d returns a compass heading for a Vector2d.
|
||||||
|
/// @param vec A vector orientation.
|
||||||
|
/// @return The compass heading of the vector in radians.
|
||||||
|
double Heading2d(Vector2d vec);
|
||||||
|
|
||||||
|
/// Heading3f returns a compass heading for a Vector2f.
|
||||||
|
/// @param vec A vector orientation.
|
||||||
|
/// @return The compass heading of the vector in radians.
|
||||||
|
float Heading3f(Vector3f vec);
|
||||||
|
|
||||||
|
/// Heading3d returns a compass heading for a Vector2f.
|
||||||
|
/// @param vec A vector orientation.
|
||||||
|
/// @return The compass heading of the vector in radians.
|
||||||
|
double Heading3d(Vector3d vec);
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace geom
|
||||||
|
} // namespace math
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __WRMATH_ORIENTATION_H
|
|
@ -0,0 +1,520 @@
|
||||||
|
/// quaternion.h contains an implementation of quaternions suitable
|
||||||
|
/// for navigation in R3.
|
||||||
|
#ifndef SCMATH_QUATERNION_H
|
||||||
|
#define SCMATH_QUATERNION_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
#include <scccl/math/geom/vector.h>
|
||||||
|
|
||||||
|
/// math contains the shimmering clarity math library.
|
||||||
|
namespace scmath {
|
||||||
|
/// geom contains geometric classes and functions.
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Quaternions provide a representation of orientation and rotations
|
||||||
|
/// in three dimensions.
|
||||||
|
///
|
||||||
|
/// Quaternions encode rotations in three-dimensional space. While technically
|
||||||
|
/// a quaternion is comprised of a real element and a complex vector<3>, for
|
||||||
|
/// the purposes of this library, it is modeled as a floating point 4D vector
|
||||||
|
/// of the form <w, x, y, z>, where x, y, and z represent an axis of rotation in
|
||||||
|
/// R3 and w the angle, in radians, of the rotation about that axis. Where Euler
|
||||||
|
/// angles are concerned, the ZYX (or yaw, pitch, roll) sequence is used.
|
||||||
|
///
|
||||||
|
/// For information on the underlying vector type, see the documentation for
|
||||||
|
/// wr::geom::Vector.
|
||||||
|
///
|
||||||
|
/// The constructors are primarily intended for intended operations; in practice,
|
||||||
|
/// the quaternionf() and quaterniond() functions are more useful for constructing
|
||||||
|
/// quaternions from vectors and angles.
|
||||||
|
///
|
||||||
|
/// Like vectors, quaternions carry an internal tolerance value ε that is used for
|
||||||
|
/// floating point comparisons. The math namespace contains the default values
|
||||||
|
/// used for this; generally, a tolerance of 0.0001 is considered appropriate for
|
||||||
|
/// the uses of this library. The tolerance can be explicitly set with the
|
||||||
|
/// setEpsilon method.
|
||||||
|
template<typename T>
|
||||||
|
class Quaternion {
|
||||||
|
public:
|
||||||
|
/// The default Quaternion constructor returns an identity quaternion.
|
||||||
|
Quaternion() : v(Vector<T, 3>{0.0, 0.0, 0.0}), w(1.0)
|
||||||
|
{
|
||||||
|
scmath::DefaultEpsilon(this->eps);
|
||||||
|
v.setEpsilon(this->eps);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A Quaternion may be initialised with a Vector<T, 3> axis of rotation
|
||||||
|
/// and an angle of rotation. This doesn't do the angle transforms to simplify
|
||||||
|
/// internal operations.
|
||||||
|
///
|
||||||
|
/// @param _axis A three-dimensional vector of the same type as the Quaternion.
|
||||||
|
/// @param _angle The angle of rotation about the axis of rotation.
|
||||||
|
Quaternion(Vector<T, 3> _axis, T _angle) : v(_axis), w(_angle)
|
||||||
|
{
|
||||||
|
this->constrainAngle();
|
||||||
|
scmath::DefaultEpsilon(this->eps);
|
||||||
|
v.setEpsilon(this->eps);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A Quaternion may be initialised with a Vector<T, 4> comprised of
|
||||||
|
/// the axis of rotation followed by the angle of rotation.
|
||||||
|
///
|
||||||
|
/// @param vector A vector in the form <w, x, y, z>.
|
||||||
|
Quaternion(Vector<T, 4> vector) :
|
||||||
|
v(Vector<T, 3>{vector[1], vector[2], vector[3]}),
|
||||||
|
w(vector[0])
|
||||||
|
{
|
||||||
|
this->constrainAngle();
|
||||||
|
scmath::DefaultEpsilon(this->eps);
|
||||||
|
v.setEpsilon(this->eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A Quaternion may be constructed with an initializer list of
|
||||||
|
/// type T, which must have exactly N elements.
|
||||||
|
///
|
||||||
|
/// @param ilst An initial set of values in the form <w, x, y, z>.
|
||||||
|
Quaternion(std::initializer_list<T> ilst)
|
||||||
|
{
|
||||||
|
auto it = ilst.begin();
|
||||||
|
|
||||||
|
this->v = Vector<T, 3>{it[1], it[2], it[3]};
|
||||||
|
this->w = it[0];
|
||||||
|
|
||||||
|
this->constrainAngle();
|
||||||
|
scmath::DefaultEpsilon(this->eps);
|
||||||
|
v.setEpsilon(this->eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Set the comparison tolerance for this quaternion.
|
||||||
|
///
|
||||||
|
/// @param epsilon A tolerance value.
|
||||||
|
void
|
||||||
|
setEpsilon(T epsilon)
|
||||||
|
{
|
||||||
|
this->eps = epsilon;
|
||||||
|
this->v.setEpsilon(epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return the axis of rotation of this quaternion.
|
||||||
|
///
|
||||||
|
/// @return The axis of rotation of this quaternion.
|
||||||
|
Vector<T, 3>
|
||||||
|
axis() const
|
||||||
|
{
|
||||||
|
return this->v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return the angle of rotation of this quaternion.
|
||||||
|
///
|
||||||
|
/// @return the angle of rotation of this quaternion.
|
||||||
|
T
|
||||||
|
angle() const
|
||||||
|
{
|
||||||
|
return this->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute the dot product of two quaternions.
|
||||||
|
///
|
||||||
|
/// \param other Another quaternion.
|
||||||
|
/// \return The dot product between the two quaternions.
|
||||||
|
T
|
||||||
|
dot(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
double innerProduct = this->v[0] * other.v[0];
|
||||||
|
|
||||||
|
innerProduct += (this->v[1] * other.v[1]);
|
||||||
|
innerProduct += (this->v[2] * other.v[2]);
|
||||||
|
innerProduct += (this->w * other.w);
|
||||||
|
return innerProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute the norm of a quaternion. Treating the Quaternion as a
|
||||||
|
/// Vector<T, 4>, it's the same as computing the magnitude.
|
||||||
|
///
|
||||||
|
/// @return A non-negative real number.
|
||||||
|
T
|
||||||
|
norm() const
|
||||||
|
{
|
||||||
|
T n = 0;
|
||||||
|
|
||||||
|
n += (this->v[0] * this->v[0]);
|
||||||
|
n += (this->v[1] * this->v[1]);
|
||||||
|
n += (this->v[2] * this->v[2]);
|
||||||
|
n += (this->w * this->w);
|
||||||
|
|
||||||
|
return std::sqrt(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return the unit quaternion.
|
||||||
|
///
|
||||||
|
/// \return The unit quaternion.
|
||||||
|
Quaternion
|
||||||
|
unitQuaternion()
|
||||||
|
{
|
||||||
|
return *this / this->norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the conjugate of a quaternion.
|
||||||
|
///
|
||||||
|
/// @return The conjugate of this quaternion.
|
||||||
|
Quaternion
|
||||||
|
conjugate() const
|
||||||
|
{
|
||||||
|
return Quaternion(Vector<T, 4>{this->w, -this->v[0], -this->v[1], -this->v[2]});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute the inverse of a quaternion.
|
||||||
|
///
|
||||||
|
/// @return The inverse of this quaternion.
|
||||||
|
Quaternion
|
||||||
|
inverse() const
|
||||||
|
{
|
||||||
|
T _norm = this->norm();
|
||||||
|
|
||||||
|
return this->conjugate() / (_norm * _norm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Determine whether this is an identity quaternion.
|
||||||
|
///
|
||||||
|
/// \return true if this is an identity quaternion.
|
||||||
|
bool
|
||||||
|
isIdentity() const {
|
||||||
|
return this->v.isZero() &&
|
||||||
|
scmath::WithinTolerance(this->w, (T)1.0, this->eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Determine whether this is a unit quaternion.
|
||||||
|
///
|
||||||
|
/// @return true if this is a unit quaternion.
|
||||||
|
bool
|
||||||
|
isUnitQuaternion() const
|
||||||
|
{
|
||||||
|
return scmath::WithinTolerance(this->norm(), (T) 1.0, this->eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return the quaternion as a Vector<T, 4>, with the axis of rotation
|
||||||
|
/// followed by the angle of rotation.
|
||||||
|
///
|
||||||
|
/// @return A vector representation of the quaternion.
|
||||||
|
Vector<T, 4>
|
||||||
|
asVector() const
|
||||||
|
{
|
||||||
|
return Vector<T, 4>{this->w, this->v[0], this->v[1], this->v[2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Rotate vector vr about this quaternion.
|
||||||
|
///
|
||||||
|
/// @param vr The vector to be rotated.
|
||||||
|
/// @return The rotated vector.
|
||||||
|
Vector<T, 3>
|
||||||
|
rotate(Vector<T, 3> vr) const
|
||||||
|
{
|
||||||
|
return (this->conjugate() * vr * (*this)).axis();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Return the Euler angles for this quaternion as a vector of
|
||||||
|
/// <yaw, pitch, roll>. Users of this function should watch out
|
||||||
|
/// for gimbal lock.
|
||||||
|
///
|
||||||
|
/// @return A vector<T, 3> containing <yaw, pitch, roll>
|
||||||
|
Vector<T, 3>
|
||||||
|
euler() const
|
||||||
|
{
|
||||||
|
T yaw, pitch, roll;
|
||||||
|
T a = this->w, a2 = a * a;
|
||||||
|
T b = this->v[0], b2 = b * b;
|
||||||
|
T c = this->v[1], c2 = c * c;
|
||||||
|
T d = this->v[2], d2 = d * d;
|
||||||
|
|
||||||
|
yaw = std::atan2(2 * ((a * b) + (c * d)), a2 - b2 - c2 + d2);
|
||||||
|
pitch = std::asin(2 * ((b * d) - (a * c)));
|
||||||
|
roll = std::atan2(2 * ((a * d) + (b * c)), a2 + b2 - c2 - d2);
|
||||||
|
|
||||||
|
return Vector<T, 3>{yaw, pitch, roll};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion addition with another quaternion.
|
||||||
|
///
|
||||||
|
/// @param other The quaternion to be added with this one.
|
||||||
|
/// @return The result of adding the two quaternions together.
|
||||||
|
Quaternion
|
||||||
|
operator+(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
return Quaternion(this->v + other.v, this->w + other.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion subtraction with another quaternion.
|
||||||
|
///
|
||||||
|
/// @param other The quaternion to be subtracted from this one.
|
||||||
|
/// @return The result of subtracting the other quaternion from this one.
|
||||||
|
Quaternion
|
||||||
|
operator-(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
return Quaternion(this->v - other.v, this->w - other.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform scalar multiplication.
|
||||||
|
///
|
||||||
|
/// @param k The scaling value.
|
||||||
|
/// @return A scaled quaternion.
|
||||||
|
Quaternion
|
||||||
|
operator*(const T k) const
|
||||||
|
{
|
||||||
|
return Quaternion(this->v * k, this->w * k);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform scalar division.
|
||||||
|
///
|
||||||
|
/// @param k The scalar divisor.
|
||||||
|
/// @return A scaled quaternion.
|
||||||
|
Quaternion
|
||||||
|
operator/(const T k) const
|
||||||
|
{
|
||||||
|
return Quaternion(this->v / k, this->w / k);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion Hamilton multiplication with a three-
|
||||||
|
/// dimensional vector; this is done by treating the vector
|
||||||
|
/// as a pure quaternion (e.g. with an angle of rotation of 0).
|
||||||
|
///
|
||||||
|
/// @param vector The vector to multiply with this quaternion.
|
||||||
|
/// @return The Hamilton product of the quaternion and vector.
|
||||||
|
Quaternion
|
||||||
|
operator*(const Vector<T, 3> &vector) const
|
||||||
|
{
|
||||||
|
return Quaternion(vector * this->w + this->v.cross(vector),
|
||||||
|
(T) 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion Hamilton multiplication.
|
||||||
|
///
|
||||||
|
/// @param other The other quaternion to multiply with this one.
|
||||||
|
/// @result The Hamilton product of the two quaternions.
|
||||||
|
Quaternion
|
||||||
|
operator*(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
T angle = (this->w * other.w) -
|
||||||
|
(this->v * other.v);
|
||||||
|
Vector<T, 3> axis = (other.v * this->w) +
|
||||||
|
(this->v * other.w) +
|
||||||
|
(this->v.cross(other.v));
|
||||||
|
return Quaternion(axis, angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion equality checking.
|
||||||
|
/// @param other The quaternion to check equality against.
|
||||||
|
/// @return True if the two quaternions are equal within their tolerance.
|
||||||
|
bool
|
||||||
|
operator==(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
return (this->v == other.v) &&
|
||||||
|
(scmath::WithinTolerance(this->w, other.w, this->eps));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Perform quaternion inequality checking.
|
||||||
|
///
|
||||||
|
/// @param other The quaternion to check inequality against.
|
||||||
|
/// @return True if the two quaternions are unequal within their tolerance.
|
||||||
|
bool
|
||||||
|
operator!=(const Quaternion<T> &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Support stream output of a quaternion in the form `a + <i, j, k>`.
|
||||||
|
/// \todo improve the formatting.
|
||||||
|
///
|
||||||
|
/// @param outs An output stream
|
||||||
|
/// @param q A quaternion
|
||||||
|
/// @return The output stream
|
||||||
|
friend std::ostream &
|
||||||
|
operator<<(std::ostream &outs, const Quaternion<T> &q)
|
||||||
|
{
|
||||||
|
outs << q.w << " + " << q.v;
|
||||||
|
return outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr T minRotation = -4 * M_PI;
|
||||||
|
static constexpr T maxRotation = 4 * M_PI;
|
||||||
|
|
||||||
|
Vector<T, 3> v; // axis of rotation
|
||||||
|
T w; // angle of rotation
|
||||||
|
T eps;
|
||||||
|
|
||||||
|
void
|
||||||
|
constrainAngle()
|
||||||
|
{
|
||||||
|
if (this->w < 0.0) {
|
||||||
|
this->w = std::fmod(this->w, this->minRotation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->w = std::fmod(this->w, this->maxRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \defgroup quaternion_aliases Quaternion type aliases.
|
||||||
|
/// Type aliases are provided for float and double quaternions.
|
||||||
|
///
|
||||||
|
|
||||||
|
/// \ingroup quaternion_aliases
|
||||||
|
/// Type alias for a float Quaternion.
|
||||||
|
typedef Quaternion<float> Quaternionf;
|
||||||
|
|
||||||
|
/// \ingroup quaternion_aliases
|
||||||
|
/// Type alias for a double Quaternion.
|
||||||
|
typedef Quaternion<double> Quaterniond;
|
||||||
|
|
||||||
|
|
||||||
|
/// Return a float quaternion scaled appropriately from a vector and angle,
|
||||||
|
/// e.g. angle = cos(angle / 2), axis.unitVector() * sin(angle / 2).
|
||||||
|
///
|
||||||
|
/// @param axis The axis of rotation.
|
||||||
|
/// @param angle The angle of rotation.
|
||||||
|
/// @return A quaternion.
|
||||||
|
/// @relatesalso Quaternion
|
||||||
|
Quaternionf quaternionf(Vector3f axis, float angle);
|
||||||
|
|
||||||
|
|
||||||
|
/// Return a double quaternion scaled appropriately from a vector and angle,
|
||||||
|
/// e.g. angle = cos(angle / 2), axis.unitVector() * sin(angle / 2).
|
||||||
|
///
|
||||||
|
/// @param axis The axis of rotation.
|
||||||
|
/// @param angle The angle of rotation.
|
||||||
|
/// @return A quaternion.
|
||||||
|
/// @relatesalso Quaternion
|
||||||
|
Quaterniond quaterniond(Vector3d axis, double angle);
|
||||||
|
|
||||||
|
|
||||||
|
/// Return a double quaternion scaled appropriately from a vector and angle,
|
||||||
|
/// e.g. angle = cos(angle / 2), axis.unitVector() * sin(angle / 2).
|
||||||
|
///
|
||||||
|
/// @param axis The axis of rotation.
|
||||||
|
/// @param angle The angle of rotation.
|
||||||
|
/// @return A quaternion.
|
||||||
|
/// @relatesalso Quaternion
|
||||||
|
template <typename T>
|
||||||
|
Quaternion<T>
|
||||||
|
quaternion(Vector<T, 3> axis, T angle)
|
||||||
|
{
|
||||||
|
return Quaternion<T>(axis.unitVector() * std::sin(angle / (T)2.0),
|
||||||
|
std::cos(angle / (T)2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Given a vector of Euler angles in ZYX sequence (e.g. yaw, pitch, roll),
|
||||||
|
/// return a quaternion.
|
||||||
|
///
|
||||||
|
/// @param euler A vector Euler angle in ZYX sequence.
|
||||||
|
/// @return A Quaternion representation of the orientation represented
|
||||||
|
/// by the Euler angles.
|
||||||
|
/// @relatesalso Quaternion
|
||||||
|
Quaternionf quaternionf_from_euler(Vector3f euler);
|
||||||
|
|
||||||
|
|
||||||
|
/// Given a vector of Euler angles in ZYX sequence (e.g. yaw, pitch, roll),
|
||||||
|
/// return a quaternion.
|
||||||
|
///
|
||||||
|
/// @param euler A vector Euler angle in ZYX sequence.
|
||||||
|
/// @return A Quaternion representation of the orientation represented
|
||||||
|
/// by the Euler angles.
|
||||||
|
/// @relatesalso Quaternion
|
||||||
|
Quaterniond quaterniond_from_euler(Vector3d euler);
|
||||||
|
|
||||||
|
|
||||||
|
/// LERP computes the linear interpolation of two quaternions at some
|
||||||
|
/// fraction of the distance between them.
|
||||||
|
///
|
||||||
|
/// \tparam T
|
||||||
|
/// \param p The starting quaternion.
|
||||||
|
/// \param q The ending quaternion.
|
||||||
|
/// \param t The fraction of the distance between the two quaternions to
|
||||||
|
/// interpolate.
|
||||||
|
/// \return A Quaternion representing the linear interpolation of the
|
||||||
|
/// two quaternions.
|
||||||
|
template <typename T>
|
||||||
|
Quaternion<T>
|
||||||
|
LERP(Quaternion<T> p, Quaternion<T> q, T t)
|
||||||
|
{
|
||||||
|
return (p + (q - p) * t).unitQuaternion();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ShortestSLERP computes the shortest distance spherical linear
|
||||||
|
/// interpolation between two quaternions at some fraction of the
|
||||||
|
/// distance between them.
|
||||||
|
///
|
||||||
|
/// \tparam T
|
||||||
|
/// \param p The starting quaternion.
|
||||||
|
/// \param q The ending quaternion.Short
|
||||||
|
/// \param t The fraction of the distance between the two quaternions
|
||||||
|
/// to interpolate.
|
||||||
|
/// \return A Quaternion representing the shortest path between two
|
||||||
|
/// quaternions.
|
||||||
|
template <typename T>
|
||||||
|
Quaternion<T>
|
||||||
|
ShortestSLERP(Quaternion<T> p, Quaternion<T> q, T t)
|
||||||
|
{
|
||||||
|
assert(p.isUnitQuaternion());
|
||||||
|
assert(q.isUnitQuaternion());
|
||||||
|
|
||||||
|
T dp = p.dot(q);
|
||||||
|
T sign = dp < 0.0 ? -1.0 : 1.0;
|
||||||
|
T omega = std::acos(dp * sign);
|
||||||
|
T sin_omega = std::sin(omega); // Compute once.
|
||||||
|
|
||||||
|
if (dp > 0.99999) {
|
||||||
|
return LERP(p, q * sign, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (p * std::sin((1.0 - t) * omega) / sin_omega) +
|
||||||
|
(q * sign * std::sin(omega*t) / sin_omega);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Run a quick self test to exercise basic functionality of the Quaternion
|
||||||
|
/// class to verify correct operation. Note that if \#NDEBUG is defined, the
|
||||||
|
/// self test is disabled.
|
||||||
|
void Quaternion_SelfTest();
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace geom
|
||||||
|
} // namespace wr
|
||||||
|
|
||||||
|
|
||||||
|
#endif // WRMATH_QUATERNION_H
|
|
@ -0,0 +1,422 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/math/vectors.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: math::vectors.
|
||||||
|
//
|
||||||
|
// vectors.h defines the Vector2D class and associated functions in the
|
||||||
|
// namespace math::vectors.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef SCMATH_VECTORS_H
|
||||||
|
#define SCMATH_VECTORS_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <ostream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
|
||||||
|
|
||||||
|
// This implementation is essentially a C++ translation of a Python library
|
||||||
|
// I wrote for Coursera's "Linear Algebra for Machine Learning" course. Many
|
||||||
|
// of the test vectors come from quiz questions in the class.
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Vectors represent a direction and magnitude.
|
||||||
|
///
|
||||||
|
/// Vector provides a standard interface for dimensionless fixed-size
|
||||||
|
/// vectors. Once instantiated, they cannot be modified.
|
||||||
|
///
|
||||||
|
/// Note that while the class is templated, it's intended to be used with
|
||||||
|
/// floating-point types.
|
||||||
|
///
|
||||||
|
/// Vectors 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 unit vector for a given type
|
||||||
|
/// and size.
|
||||||
|
Vector()
|
||||||
|
{
|
||||||
|
T unitLength = (T)1.0 / std::sqrt(N);
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
this->arr[i] = unitLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
scmath::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 An intializer list with N elements of type T.
|
||||||
|
Vector(std::initializer_list<T> ilst)
|
||||||
|
{
|
||||||
|
assert(ilst.size() == N);
|
||||||
|
|
||||||
|
scmath::DefaultEpsilon(this->epsilon);
|
||||||
|
std::copy(ilst.begin(), ilst.end(), this->arr.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute 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 (!scmath::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 scmath::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 (scmath::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 scmath::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute the cross product of two vectors. This is only defined
|
||||||
|
/// over three-dimensional vectors.
|
||||||
|
/// @param other Another 3D vector.
|
||||||
|
/// @return The cross product vector.
|
||||||
|
Vector
|
||||||
|
cross(const Vector<T, N> &other) const
|
||||||
|
{
|
||||||
|
assert(N == 3);
|
||||||
|
return Vector<T, N> {
|
||||||
|
(this->arr[1] * other.arr[2]) - (other.arr[1] * this->arr[2]),
|
||||||
|
-((this->arr[0] * other.arr[2]) - (other.arr[0] * this->arr[2])),
|
||||||
|
(this->arr[0] * other.arr[1]) - (other.arr[0] * this->arr[1])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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 (!scmath::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.
|
||||||
|
///
|
||||||
|
/// Note that the values of the vector cannot be modified. Instead,
|
||||||
|
/// it's required to do something like the following:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// Vector3d a {1.0, 2.0, 3.0};
|
||||||
|
/// Vector3d b {a[0], a[1]*2.0, a[2]};
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// @param i The component index.
|
||||||
|
/// @return The value of the vector component at i.
|
||||||
|
const 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \defgroup vector_aliases Vector type aliases.
|
||||||
|
///
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// 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.
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a two-dimensional float vector.
|
||||||
|
typedef Vector<float, 2> Vector2f;
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a three-dimensional float vector.
|
||||||
|
typedef Vector<float, 3> Vector3f;
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a four-dimensional float vector.
|
||||||
|
typedef Vector<float, 4> Vector4f;
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a two-dimensional double vector.
|
||||||
|
typedef Vector<double, 2> Vector2d;
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a three-dimensional double vector.
|
||||||
|
typedef Vector<double, 3> Vector3d;
|
||||||
|
|
||||||
|
/// \ingroup vector_aliases
|
||||||
|
/// @brief Type alias for a four-dimensional double vector.
|
||||||
|
typedef Vector<double, 4> Vector4d;
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace geom
|
||||||
|
} // namespace math
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SCMATH_VECTORS_H_H
|
|
@ -0,0 +1,77 @@
|
||||||
|
/// math.h provides certain useful mathematical functions.
|
||||||
|
|
||||||
|
#ifndef SCCCL_MATH_H
|
||||||
|
#define SCCCL_MATH_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
|
||||||
|
|
||||||
|
// MAX_RADIAN is a precomputed 2 * M_PI, and MIN_RADIAN is -2 * M_PI.
|
||||||
|
constexpr double MAX_RADIAN = 2 * M_PI;
|
||||||
|
constexpr double MIN_RADIAN = -2 * M_PI;
|
||||||
|
constexpr double POS_HALF_RADIAN = M_PI / 2;
|
||||||
|
constexpr double NEG_HALF_RADIAN = -(M_PI / 2);
|
||||||
|
|
||||||
|
|
||||||
|
/// Roll m die of n sides, returning a vector of the dice.
|
||||||
|
std::vector<int> Die(int m, int n);
|
||||||
|
/// Roll m die of n sides, returning the total of the die.
|
||||||
|
int DieTotal(int m, int n);
|
||||||
|
/// Roll m die of n sides, and take the total of the top k die.
|
||||||
|
int BestDie(int k, int m, int n);
|
||||||
|
|
||||||
|
|
||||||
|
/// Convert radians to degrees.
|
||||||
|
/// @param rads the angle in radians
|
||||||
|
/// @return the angle in degrees.
|
||||||
|
float RadiansToDegreesF(float rads);
|
||||||
|
|
||||||
|
/// Convert radians to degrees.
|
||||||
|
/// @param rads the angle in radians
|
||||||
|
/// @return the angle in degrees.
|
||||||
|
double RadiansToDegreesD(double rads);
|
||||||
|
|
||||||
|
/// Convert degrees to radians.
|
||||||
|
/// @param degrees the angle in degrees
|
||||||
|
/// @return the angle in radians.
|
||||||
|
float DegreesToRadiansF(float degrees);
|
||||||
|
|
||||||
|
/// Convert degrees to radians.
|
||||||
|
/// @param degrees the angle in degrees
|
||||||
|
/// @return the angle in radians.
|
||||||
|
double DegreesToRadiansD(double degrees);
|
||||||
|
|
||||||
|
/// RotateRadians rotates theta0 by theta1 radians, wrapping the result to
|
||||||
|
/// MIN_RADIAN <= result <= MAX_RADIAN.
|
||||||
|
double RotateRadians(double theta0, double theta1);
|
||||||
|
|
||||||
|
/// Get the default epsilon value.
|
||||||
|
/// @param epsilon The variable to store the epsilon value in.
|
||||||
|
void DefaultEpsilon(double &epsilon);
|
||||||
|
|
||||||
|
/// Get the default epsilon value.
|
||||||
|
/// @param epsilon The variable to store the epsilon value in.
|
||||||
|
void DefaultEpsilon(float &epsilon);
|
||||||
|
|
||||||
|
|
||||||
|
/// Return whether the two values of type T are equal to within some tolerance.
|
||||||
|
/// @tparam T The type of value
|
||||||
|
/// @param a A value of type T used as the left-hand side of an equality check.
|
||||||
|
/// @param b A value of type T used as the right-hand side of an equality check.
|
||||||
|
/// @param epsilon The tolerance value.
|
||||||
|
/// @return Whether the two values are "close enough" to be considered equal.
|
||||||
|
template <typename T>
|
||||||
|
static T
|
||||||
|
WithinTolerance(T a, T b, T epsilon)
|
||||||
|
{
|
||||||
|
return std::abs(a - b) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace math
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SCCCL_MATH_H
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by Kyle Isom on 2/21/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCCCL_MOTION2D_H
|
||||||
|
#define SCCCL_MOTION2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <scccl/math/geom/vector.h>
|
||||||
|
|
||||||
|
namespace scphys {
|
||||||
|
namespace basic {
|
||||||
|
|
||||||
|
|
||||||
|
scmath::geom::Vector2d Acceleration(double speed, double heading);
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace basic
|
||||||
|
} // namespace phsyics
|
||||||
|
|
||||||
|
#endif //SCCCL_MOTION2D_H
|
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/test/Report.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: test
|
||||||
|
//
|
||||||
|
// Report.h defines a Report structure that contains information about
|
||||||
|
// the results of unit tests.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef __SCTEST_REPORT_H
|
||||||
|
#define __SCTEST_REPORT_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace sctest {
|
||||||
|
|
||||||
|
typedef struct _Report {
|
||||||
|
// Failing stores the number of failing tests; for tests added
|
||||||
|
// with AddTest, this is a test that returned false. For tests
|
||||||
|
// added with AddFailingTest, this is a test that returned true.
|
||||||
|
size_t Failing;
|
||||||
|
|
||||||
|
// Total is the number of tests registered during the last run.
|
||||||
|
size_t Total;
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> Start;
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> End;
|
||||||
|
std::chrono::duration<double> Duration;
|
||||||
|
|
||||||
|
_Report();
|
||||||
|
} Report;
|
||||||
|
|
||||||
|
} // end namespace test
|
||||||
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/test/SimpleSuite.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: test
|
||||||
|
//
|
||||||
|
// SimpleSuite.h defines the SimpleSuite class for unit testing.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef __SCTEST_SIMPLESUITE_H
|
||||||
|
#define __SCTEST_SIMPLESUITE_H
|
||||||
|
|
||||||
|
// SimpleSuite.h
|
||||||
|
// This header file defines the interface for a simple suite of tests.
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <sctest/Report.h>
|
||||||
|
|
||||||
|
namespace sctest {
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string name;
|
||||||
|
std::function<bool(void)> test;
|
||||||
|
} TestCase;
|
||||||
|
|
||||||
|
class SimpleSuite {
|
||||||
|
public:
|
||||||
|
SimpleSuite();
|
||||||
|
|
||||||
|
// Silence suppresses output.
|
||||||
|
void Silence(void) { quiet = true; }
|
||||||
|
|
||||||
|
// Setup defines a setup function; this should be a predicate. This function
|
||||||
|
// is called at the start of the Run method, before tests are run.
|
||||||
|
void Setup(std::function<bool(void)> setupFn) { fnSetup = setupFn; }
|
||||||
|
|
||||||
|
// Teardown defines a teardown function; this should be a predicate. This
|
||||||
|
// function is called at the end of the Run method, after all tests have run.
|
||||||
|
void Teardown(std::function<bool(void)> teardownFn) { fnTeardown = teardownFn; }
|
||||||
|
|
||||||
|
// AddTest is used to add a test that is expected to return true.
|
||||||
|
void AddTest(std::string, std::function<bool(void)>);
|
||||||
|
|
||||||
|
// AddFailingTest is used to add a test that is expected to return false.
|
||||||
|
void AddFailingTest(std::string, std::function<bool(void)>);
|
||||||
|
|
||||||
|
bool Run(void);
|
||||||
|
|
||||||
|
// Reporting methods.
|
||||||
|
|
||||||
|
// Reset clears the report statistics.
|
||||||
|
void Reset(void) { report.Failing = report.Total = 0; hasRun = false; };
|
||||||
|
|
||||||
|
// IsReportReady returns true if a report is ready.
|
||||||
|
bool IsReportReady(void) { return hasRun; }
|
||||||
|
|
||||||
|
// Report returns a Report.
|
||||||
|
Report GetReport(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool quiet;
|
||||||
|
std::function<bool(void)> fnSetup, fnTeardown;
|
||||||
|
std::vector<TestCase> tests;
|
||||||
|
|
||||||
|
// Report functions.
|
||||||
|
Report report;
|
||||||
|
bool hasRun; // Have the tests been run yet?
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace test
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/test/checks.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: test.
|
||||||
|
//
|
||||||
|
// checks.h defines a number of macros (which are global in scope) for
|
||||||
|
// use in test functions that return bools.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef __SCTEST_CHECKS_H
|
||||||
|
#define __SCTEST_CHECKS_H
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sctest {
|
||||||
|
|
||||||
|
|
||||||
|
// The following checks are designed as shortcuts that just return false on certain
|
||||||
|
// conditions.
|
||||||
|
#define SCTEST_CHECK(x) if (!(x)) { return false; }
|
||||||
|
#define SCTEST_CHECK_FALSE(x) if ((x)) { return false; }
|
||||||
|
#define SCTEST_CHECK_EQ(x, y) if ((x) != (y)) { return false; }
|
||||||
|
#define SCTEST_CHECK_NE(x, y) if ((x) == (y)) { return false; }
|
||||||
|
#define SCTEST_CHECK_ZERO(x) if ((x) != 0) { return false; }
|
||||||
|
#define SCTEST_CHECK_GTZ(x) if ((x) > 0) { return false; }
|
||||||
|
#define SCTEST_CHECK_GEZ(x) if ((x) >= 0) { return false; }
|
||||||
|
#define SCTEST_CHECK_LEZ(x) if ((x) <= 0) { return false; }
|
||||||
|
#define SCTEST_CHECK_LTZ(x) if ((x) < 0) { return false; }
|
||||||
|
#define SCTEST_CHECK_FEQ(x, y) { float eps; scmath::DefaultEpsilon(eps); if (!scmath::WithinTolerance((x), (y), eps)) { return false; }}
|
||||||
|
#define SCTEST_CHECK_DEQ(x, y) { double eps; scmath::DefaultEpsilon(eps); if (!scmath::WithinTolerance((x), (y), eps)) { return false; }}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,57 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: include/test/debug.h
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: test
|
||||||
|
//
|
||||||
|
// debug.h defines assertions and other debugging functions.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#if 0
|
||||||
|
// Disabled for now.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <cstdlib>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// GenerateCoreDumps should be set at the beginning of the program, before
|
||||||
|
// multithreading. It is *not* threadsafe.
|
||||||
|
static bool GenerateCoreDumps = false;
|
||||||
|
|
||||||
|
static void
|
||||||
|
Assert(bool cond) {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
std::cout << "Not a debug build, skipping assertion." << std::endl;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!cond) {
|
||||||
|
std::cerr << "Assertion failed in " << __func__ << "(" << __FILE__ << ":" << __LINE__ << ")" << std::endl;
|
||||||
|
if (GenerateCoreDumps) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -24,10 +24,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include "Arena.h"
|
#include <scsl/Arena.h>
|
||||||
#include "Commander.h"
|
#include <scsl/Commander.h>
|
||||||
#include "Dictionary.h"
|
#include <scsl/Dictionary.h>
|
||||||
#include "Flag.h"
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
||||||
|
|
||||||
static const char *defaultPhonebook = "pb.dat";
|
static const char *defaultPhonebook = "pb.dat";
|
|
@ -0,0 +1,181 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: src/math/geom2d.cpp
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
// Namespace: math::geom
|
||||||
|
//
|
||||||
|
// geom2d.cpp contains the implementation of 2D geometry in the math::geom
|
||||||
|
// namespace.
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
#include <scccl/math/geom/coord2d.h>
|
||||||
|
|
||||||
|
|
||||||
|
// coord2d.cpp contains 2D geometric functions and data structures, such as
|
||||||
|
// cartesian and polar coordinates and rotations.
|
||||||
|
|
||||||
|
// TODO: deprecate Point2D in favour of Vector
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Point2D
|
||||||
|
|
||||||
|
Point2D::Point2D(const Polar2D &pol)
|
||||||
|
: x(std::rint(std::cos(pol.theta) * pol.r)),
|
||||||
|
y(std::rint(std::sin(pol.theta) * pol.r)) {}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& outs, const Point2D& pt)
|
||||||
|
{
|
||||||
|
outs << "(" << std::to_string(pt.x) << ", " << std::to_string(pt.y) << ")";
|
||||||
|
return outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Point2D::ToString()
|
||||||
|
{
|
||||||
|
return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Point2D::ToPolar(Polar2D& pol)
|
||||||
|
{
|
||||||
|
pol.r = std::sqrt((x * x) + (y * y));
|
||||||
|
pol.theta = std::atan2(y, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Point2D::Rotate(Point2D& pt, double theta)
|
||||||
|
{
|
||||||
|
Polar2D pol(*this);
|
||||||
|
pol.Rotate(pol, theta);
|
||||||
|
pol.ToPoint(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Point2D::operator==(const Point2D& rhs) const
|
||||||
|
{
|
||||||
|
return (x == rhs.x) && (y == rhs.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Point2D::Translate(const Point2D& origin, Point2D &translated)
|
||||||
|
{
|
||||||
|
translated.x = origin.x + x;
|
||||||
|
translated.y = origin.y + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Point2D>
|
||||||
|
Point2D::Rotate(std::vector<Polar2D> vertices, double theta)
|
||||||
|
{
|
||||||
|
std::vector<Point2D> rotated;
|
||||||
|
|
||||||
|
for (auto v : vertices) {
|
||||||
|
Point2D p;
|
||||||
|
v.RotateAround(*this, p, theta);
|
||||||
|
rotated.push_back(p) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Point2D::Distance(const Point2D& other)
|
||||||
|
{
|
||||||
|
auto dx = other.x - x;
|
||||||
|
auto dy = other.y - y;
|
||||||
|
return std::sqrt(dx * dx + dy + dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Polar2D
|
||||||
|
|
||||||
|
Polar2D::Polar2D(const Point2D &pt)
|
||||||
|
: r(std::sqrt((pt.x * pt.x) + (pt.y * pt.y))),
|
||||||
|
theta(std::atan2(pt.y, pt.x)) {}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Polar2D::ToPoint(Point2D& pt)
|
||||||
|
{
|
||||||
|
pt.y = std::rint(std::sin(theta) * r);
|
||||||
|
pt.x = std::rint(std::cos(theta) * r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Polar2D::ToString()
|
||||||
|
{
|
||||||
|
return "(" + std::to_string(r) + ", " + std::to_string(theta) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Polar2D::Rotate(Polar2D& rot, double delta)
|
||||||
|
{
|
||||||
|
rot.r = r;
|
||||||
|
rot.theta = RotateRadians(theta, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Polar2D::operator==(const Polar2D& rhs) const
|
||||||
|
{
|
||||||
|
static double eps = 0.0;
|
||||||
|
if (eps == 0.0) {
|
||||||
|
scmath::DefaultEpsilon(eps);
|
||||||
|
}
|
||||||
|
return scmath::WithinTolerance(r, rhs.r, eps) &&
|
||||||
|
scmath::WithinTolerance(theta, rhs.theta, eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Polar2D::RotateAround(const Point2D &origin, Point2D &point, double delta)
|
||||||
|
{
|
||||||
|
Polar2D rot;
|
||||||
|
this->Rotate(rot, delta);
|
||||||
|
rot.ToPoint(point);
|
||||||
|
point.Translate(origin, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& outs, const Polar2D& pol)
|
||||||
|
{
|
||||||
|
outs << "(" << pol.r << ", " << pol.theta << ")";
|
||||||
|
return outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace geom
|
||||||
|
} // end namespace math
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <numeric>
|
||||||
|
#include <random>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<int>
|
||||||
|
Die(int m, int n)
|
||||||
|
{
|
||||||
|
std::uniform_int_distribution<> die(1, n);
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::vector<int> dice;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++) {
|
||||||
|
dice.push_back(die(rd));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
BestDie(int k, int m, int n)
|
||||||
|
{
|
||||||
|
auto dice = Die(m, n);
|
||||||
|
|
||||||
|
if (k < m) {
|
||||||
|
std::sort(dice.begin(), dice.end(), std::greater<int>());
|
||||||
|
dice.resize(static_cast<size_t>(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::accumulate(dice.begin(), dice.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
DieTotal(int m, int n)
|
||||||
|
{
|
||||||
|
std::uniform_int_distribution<> die(1, n);
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
int i = 0, total = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++) {
|
||||||
|
total += die(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
RotateRadians(double theta0, double theta1)
|
||||||
|
{
|
||||||
|
auto dtheta = theta0 + theta1;
|
||||||
|
|
||||||
|
if (dtheta > M_PI) {
|
||||||
|
dtheta -= MAX_RADIAN;
|
||||||
|
} else if (dtheta < -M_PI) {
|
||||||
|
dtheta += MAX_RADIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dtheta < -M_PI) || (dtheta > M_PI)) {
|
||||||
|
return RotateRadians(dtheta, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtheta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace math
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <cmath>
|
||||||
|
#include <scccl/phys/basic/motion2d.h>
|
||||||
|
|
||||||
|
namespace scphys {
|
||||||
|
namespace basic {
|
||||||
|
|
||||||
|
|
||||||
|
scmath::geom::Vector2d
|
||||||
|
Acceleration(double speed, double heading)
|
||||||
|
{
|
||||||
|
auto dx = std::cos(heading) * speed;
|
||||||
|
auto dy = std::sin(heading) * speed;
|
||||||
|
|
||||||
|
return scmath::geom::Vector2d({dx, dy});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace basic
|
||||||
|
} // namespace phys
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <scccl/math/geom/vector.h>
|
||||||
|
#include <scccl/math/geom/orientation.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
Heading2f(Vector2f vec)
|
||||||
|
{
|
||||||
|
return vec.angle(Basis2f[Basis_x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
Heading3f(Vector3f vec)
|
||||||
|
{
|
||||||
|
Vector2f vec2f {vec[0], vec[1]};
|
||||||
|
return Heading2f(vec2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
Heading2d(Vector2d vec)
|
||||||
|
{
|
||||||
|
return vec.angle(Basis2d[Basis_x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
Heading3d(Vector3d vec)
|
||||||
|
{
|
||||||
|
Vector2d vec2d {vec[0], vec[1]};
|
||||||
|
return Heading2d(vec2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace geom
|
||||||
|
} // namespace math
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <scccl/math/geom/quaternion.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace scmath {
|
||||||
|
namespace geom {
|
||||||
|
|
||||||
|
|
||||||
|
Quaternionf
|
||||||
|
quaternionf(Vector3f axis, float angle)
|
||||||
|
{
|
||||||
|
return Quaternionf(axis.unitVector() * std::sin(angle / 2.0),
|
||||||
|
std::cos(angle / 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Quaterniond
|
||||||
|
quaterniond(Vector3d axis, double angle)
|
||||||
|
{
|
||||||
|
return Quaterniond(axis.unitVector() * std::sin(angle / 2.0),
|
||||||
|
std::cos(angle / 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Quaternionf
|
||||||
|
quaternionf_from_euler(Vector3f euler)
|
||||||
|
{
|
||||||
|
float x, y, z, w;
|
||||||
|
euler = euler / 2.0;
|
||||||
|
|
||||||
|
float cos_yaw = std::cos(euler[0]);
|
||||||
|
float cos_pitch = std::cos(euler[1]);
|
||||||
|
float cos_roll = std::cos(euler[2]);
|
||||||
|
float sin_yaw = std::sin(euler[0]);
|
||||||
|
float sin_pitch = std::sin(euler[1]);
|
||||||
|
float sin_roll = std::sin(euler[2]);
|
||||||
|
|
||||||
|
x = (sin_yaw * cos_pitch * cos_roll) + (cos_yaw * sin_pitch * sin_roll);
|
||||||
|
y = (sin_yaw * cos_pitch * sin_roll) - (cos_yaw * sin_pitch * cos_roll);
|
||||||
|
z = (cos_yaw * cos_pitch * sin_roll) + (sin_yaw * sin_pitch * cos_roll);
|
||||||
|
w = (cos_yaw * cos_pitch * cos_roll) - (sin_yaw * sin_pitch * sin_roll);
|
||||||
|
|
||||||
|
return Quaternionf(Vector4f{w, x, y, z});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Quaterniond
|
||||||
|
quaterniond_from_euler(Vector3d euler)
|
||||||
|
{
|
||||||
|
double x, y, z, w;
|
||||||
|
euler = euler / 2.0;
|
||||||
|
|
||||||
|
double cos_yaw = std::cos(euler[0]);
|
||||||
|
double cos_pitch = std::cos(euler[1]);
|
||||||
|
double cos_roll = std::cos(euler[2]);
|
||||||
|
double sin_yaw = std::sin(euler[0]);
|
||||||
|
double sin_pitch = std::sin(euler[1]);
|
||||||
|
double sin_roll = std::sin(euler[2]);
|
||||||
|
|
||||||
|
x = (sin_yaw * cos_pitch * cos_roll) + (cos_yaw * sin_pitch * sin_roll);
|
||||||
|
y = (sin_yaw * cos_pitch * sin_roll) - (cos_yaw * sin_pitch * cos_roll);
|
||||||
|
z = (cos_yaw * cos_pitch * sin_roll) + (sin_yaw * sin_pitch * cos_roll);
|
||||||
|
w = (cos_yaw * cos_pitch * cos_roll) - (sin_yaw * sin_pitch * sin_roll);
|
||||||
|
|
||||||
|
return Quaterniond(Vector4d{w, x, y, z});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Quaternion_SelfTest()
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
Vector3f v {1.0, 0.0, 0.0};
|
||||||
|
Vector3f yAxis {0.0, 1.0, 0.0};
|
||||||
|
float angle = M_PI / 2;
|
||||||
|
|
||||||
|
Quaternionf p = quaternionf(yAxis, angle);
|
||||||
|
Quaternionf q;
|
||||||
|
Vector3f vr {0.0, 0.0, 1.0};
|
||||||
|
|
||||||
|
assert(p.isUnitQuaternion());
|
||||||
|
std::cerr << p.rotate(v) << std::endl;
|
||||||
|
assert(p.rotate(v) == vr);
|
||||||
|
assert(p * q == p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace geom
|
||||||
|
} // namespace math
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
|
||||||
#include "Arena.h"
|
#include <scsl/Arena.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
|
@ -26,7 +26,8 @@
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include <scsl/Buffer.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Commander.h"
|
#include <scsl/Commander.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
|
@ -24,7 +24,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "Dictionary.h"
|
#include <scsl/Dictionary.h>
|
||||||
|
|
||||||
#if defined(SCSL_DESKTOP_BUILD)
|
#if defined(SCSL_DESKTOP_BUILD)
|
||||||
#include <iostream>
|
#include <iostream>
|
|
@ -20,7 +20,7 @@
|
||||||
/// PERFORMANCE OF THIS SOFTWARE.
|
/// PERFORMANCE OF THIS SOFTWARE.
|
||||||
///
|
///
|
||||||
|
|
||||||
#include "Exceptions.h"
|
#include <scsl/Exceptions.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
|
@ -25,8 +25,8 @@
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Flag.h"
|
#include <scsl/Flag.h>
|
||||||
#include "StringUtil.h"
|
#include <scsl/StringUtil.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <scccl/math/math.h>
|
||||||
|
using namespace std;
|
||||||
|
using namespace scmath;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
rollDie(char *s)
|
||||||
|
{
|
||||||
|
int m = 0, n = 0;
|
||||||
|
int i = 0;
|
||||||
|
bool readSides = false;
|
||||||
|
|
||||||
|
while (s[i] != '\0') {
|
||||||
|
if (s[i] != 'd' && !isdigit(s[i])) {
|
||||||
|
cerr << "Invalid die specification!" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readSides) {
|
||||||
|
if (s[i] == 'd') {
|
||||||
|
cerr << "Invalid die specification!" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n *= 10;
|
||||||
|
n += (s[i] - 0x30);
|
||||||
|
} else {
|
||||||
|
if (s[i] == 'd') {
|
||||||
|
readSides = true;
|
||||||
|
} else {
|
||||||
|
m *= 10;
|
||||||
|
m += (s[i] - 0x30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m == 0) {
|
||||||
|
m = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << s << ": " << DieTotal(m, n) << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
rollPlayer()
|
||||||
|
{
|
||||||
|
vector<string> statNames = {"STR", "CON", "DEX", "INT", "PER"};
|
||||||
|
vector<int> statRolls;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < statNames.size(); i++) {
|
||||||
|
statRolls.push_back(BestDie(3, 4, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < statNames.size(); i++) {
|
||||||
|
cout << statNames[i] << ": " << statRolls[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (string(argv[i]) == "player") {
|
||||||
|
rollPlayer();
|
||||||
|
} else {
|
||||||
|
rollDie(argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include <scsl/StringUtil.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scsl {
|
namespace scsl {
|
|
@ -23,7 +23,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "TLV.h"
|
#include <scsl/TLV.h>
|
||||||
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
/// PERFORMANCE OF THIS SOFTWARE.
|
/// PERFORMANCE OF THIS SOFTWARE.
|
||||||
///
|
///
|
||||||
|
|
||||||
#include "Exceptions.h"
|
#include <scsl/Exceptions.h>
|
||||||
#include "Test.h"
|
#include <sctest/Assert.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
|
@ -0,0 +1,37 @@
|
||||||
|
///
|
||||||
|
/// \file src/test/Report.cpp
|
||||||
|
/// \author Kyle Isom
|
||||||
|
/// \date 2017-06-07
|
||||||
|
///
|
||||||
|
/// \brief Defines a Report structure that contains information about
|
||||||
|
/// the results of unit tests.
|
||||||
|
///
|
||||||
|
/// Copyright 2017 K. Isom <kyle@imap.cc>
|
||||||
|
///
|
||||||
|
/// Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
/// any purpose with or without fee is hereby granted, provided that
|
||||||
|
/// the above copyright notice and this permission notice appear in all /// copies.
|
||||||
|
///
|
||||||
|
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
/// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <sctest/Report.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sctest {
|
||||||
|
|
||||||
|
|
||||||
|
_Report::_Report()
|
||||||
|
: Failing (0), Total(0), Start(std::chrono::steady_clock::now()),
|
||||||
|
End(std::chrono::steady_clock::now()), Duration(0) {}
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace test
|
|
@ -0,0 +1,108 @@
|
||||||
|
///
|
||||||
|
/// \file SimpleSuite.cc
|
||||||
|
/// \author K. Isom <kyle@imap.cc>
|
||||||
|
/// \date 2017-06-05
|
||||||
|
/// \brief Defines a simple unit testing framework.
|
||||||
|
///
|
||||||
|
/// Copyright 2017 K. Isom <kyle@imap.cc>
|
||||||
|
///
|
||||||
|
/// Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
/// any purpose with or without fee is hereby granted, provided that
|
||||||
|
/// the above copyright notice and this permission notice appear in all /// copies.
|
||||||
|
///
|
||||||
|
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
/// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <sctest/SimpleSuite.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sctest {
|
||||||
|
|
||||||
|
#define unless(cond) if (!(cond))
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
stub()
|
||||||
|
{ return true; }
|
||||||
|
|
||||||
|
SimpleSuite::SimpleSuite()
|
||||||
|
: quiet(false), fnSetup(stub), fnTeardown(stub), tests(),
|
||||||
|
report(), hasRun(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SimpleSuite::AddTest(std::string name, std::function<bool()> test)
|
||||||
|
{
|
||||||
|
TestCase test_case = {name, test};
|
||||||
|
tests.push_back(test_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SimpleSuite::AddFailingTest(std::string name, std::function<bool()> test)
|
||||||
|
{
|
||||||
|
// auto ntest = [&test]() { return !test(); };
|
||||||
|
TestCase test_case = {name, [&test]() { return !test(); }};
|
||||||
|
tests.push_back(test_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SimpleSuite::Run()
|
||||||
|
{
|
||||||
|
report.Start = std::chrono::steady_clock::now();
|
||||||
|
unless(quiet) { std::cout << "Setting up the tests.\n"; }
|
||||||
|
unless(fnSetup()) { return false; }
|
||||||
|
|
||||||
|
// Reset the failed test counts.
|
||||||
|
report.Failing = 0;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
hasRun = true;
|
||||||
|
report.Total = tests.size();
|
||||||
|
for (size_t i = 0; i < report.Total && result; i++) {
|
||||||
|
TestCase tc = tests.at(i);
|
||||||
|
unless(quiet) {
|
||||||
|
std::cout << "[" << i + 1 << "/" << report.Total << "] Running test " << tc.name << ": ";
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tc.test();
|
||||||
|
if (quiet) { continue; }
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
std::cout << "[PASS]";
|
||||||
|
} else {
|
||||||
|
std::cout << "[FAIL]";
|
||||||
|
report.Failing++;
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
unless(quiet) { std::cout << "Tearing down the tests.\n"; }
|
||||||
|
unless(fnTeardown()) { return false; }
|
||||||
|
report.End = std::chrono::steady_clock::now();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Report
|
||||||
|
SimpleSuite::GetReport()
|
||||||
|
{
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end namespace sctest
|
|
@ -1,7 +1,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include <scsl/Buffer.h>
|
||||||
using namespace scsl;
|
using namespace scsl;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Arena.h"
|
#include <scsl/Arena.h>
|
||||||
#include "Dictionary.h"
|
#include <scsl/Dictionary.h>
|
||||||
#include "Test.h"
|
#include <sctest/Assert.h>
|
||||||
#include "testFixtures.h"
|
#include "test_fixtures.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Flag.h"
|
#include <scsl/Flag.h>
|
||||||
#include "Test.h"
|
#include <sctest/Assert.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
// Project: scccl
|
||||||
|
// File: test/math/simple_suite_example.cpp
|
||||||
|
// Author: Kyle Isom
|
||||||
|
// Date: 2017-06-05
|
||||||
|
//
|
||||||
|
// simple_suite_example demonstrates the usage of the SimpleSuite test class
|
||||||
|
// and serves to unit test the unit tester (qui custodiet ipsos custodes)?
|
||||||
|
//
|
||||||
|
// Copyright 2017 Kyle Isom <kyle@imap.cc>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <sctest/SimpleSuite.h>
|
||||||
|
|
||||||
|
static bool
|
||||||
|
prepareTests()
|
||||||
|
{
|
||||||
|
std::cout << "time passes...\n";
|
||||||
|
std::cout << "tests are ready.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
destroyTests()
|
||||||
|
{
|
||||||
|
std::cout << "time passes...\n" ;
|
||||||
|
std::cout << "tests have been destroyed.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool addOne() { return 1 + 1 == 2; }
|
||||||
|
static bool four() { return 2 + 2 == 4; }
|
||||||
|
static bool nope() { return 2 + 2 == 5; }
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
sctest::SimpleSuite TestSuite;
|
||||||
|
TestSuite.Setup(prepareTests);
|
||||||
|
TestSuite.Teardown(destroyTests);
|
||||||
|
TestSuite.AddTest("1 + 1", addOne);
|
||||||
|
TestSuite.AddTest("fourness", four);
|
||||||
|
TestSuite.AddFailingTest("self-evident truth", nope);
|
||||||
|
|
||||||
|
bool result = TestSuite.Run();
|
||||||
|
if (TestSuite.IsReportReady()) {
|
||||||
|
auto report = TestSuite.GetReport();
|
||||||
|
std::cout << report.Failing << " / " << report.Total;
|
||||||
|
std::cout << " tests failed.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,8 +24,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include <scsl/StringUtil.h>
|
||||||
#include "Test.h"
|
#include <sctest/Assert.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "TLV.h"
|
#include <scsl/TLV.h>
|
||||||
|
|
||||||
|
|
||||||
#define ARENA_SIZE 128
|
#define ARENA_SIZE 128
|
|
@ -3,11 +3,11 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "Arena.h"
|
#include <scsl/Arena.h>
|
||||||
#include "Test.h"
|
#include <scsl/TLV.h>
|
||||||
#include "TLV.h"
|
#include <sctest/Assert.h>
|
||||||
|
|
||||||
#include "testFixtures.h"
|
#include "test_fixtures.h"
|
||||||
|
|
||||||
using namespace scsl;
|
using namespace scsl;
|
||||||
|
|
Loading…
Reference in New Issue