clang-tidy fixes, documentation, refactoring.

This commit is contained in:
Kyle Isom 2023-10-21 02:07:59 -07:00
parent 4e83da345f
commit aee337f2e9
26 changed files with 325 additions and 238 deletions

View File

@ -7,6 +7,7 @@ Checks: >-
performance-*,
readability-*,
-bugprone-lambda-function-name,
-bugprone-easily-swappable-parameters,
-bugprone-reserved-identifier,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-avoid-magic-numbers,
@ -21,6 +22,7 @@ Checks: >-
-modernize-use-nodiscard,
-modernize-use-trailing-return-type,
-performance-unnecessary-value-param,
-readability-identifier-length,
-readability-magic-numbers
CheckOptions:

View File

@ -41,23 +41,27 @@ set(HEADER_FILES
include/scsl/Buffer.h
include/scsl/Commander.h
include/scsl/Dictionary.h
include/sctest/Exceptions.h
include/scsl/Flags.h
include/scsl/StringUtil.h
include/scsl/TLV.h
include/scmp/estimation.h
include/scmp/geom.h
include/scmp/scmp.h
include/scmp/Math.h
include/scmp/Motion2D.h
include/scmp/geom/Coord2D.h
include/scmp/geom/Orientation.h
include/scmp/geom/Quaternion.h
include/scmp/geom/Vector.h
include/scmp/filter/Madgwick.h
include/scmp/estimation/Madgwick.h
include/sctest/sctest.h
include/sctest/Assert.h
include/sctest/Checks.h
include/sctest/Debug.h
include/sctest/Exceptions.h
include/sctest/Report.h
include/sctest/SimpleSuite.h
)
include_directories(include)
@ -74,7 +78,6 @@ set(SOURCE_FILES
src/scmp/Math.cc
src/scmp/Coord2D.cc
src/scmp/Motion2D.cc
src/scmp/Orientation.cc
src/scmp/Quaternion.cc

View File

@ -22,8 +22,8 @@
/// PERFORMANCE OF THIS SOFTWARE.
///
#ifndef SCCCL_MATH_H
#define SCCCL_MATH_H
#ifndef SCSL_SCMP_MATH_H
#define SCSL_SCMP_MATH_H
#include <cmath>
#include <vector>
@ -118,4 +118,4 @@ WithinTolerance(T a, T b, T epsilon)
} // namespace scmp
#endif //SCCCL_MATH_H
#endif //SCSL_SCMP_MATH_H

View File

@ -1,21 +0,0 @@
//
// Created by Kyle Isom on 2/21/20.
//
#ifndef SCCCL_MOTION2D_H
#define SCCCL_MOTION2D_H
#include <scmp/geom/Vector.h>
namespace scmp {
namespace basic {
scmp::geom::Vector2D Acceleration(double speed, double heading);
} // namespace basic
} // namespace phsyics
#endif //SCCCL_MOTION2D_H

39
include/scmp/estimation.h Normal file
View File

@ -0,0 +1,39 @@
///
/// \file include/scmp/estimation.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-20
/// \brief
///
/// Copyright 2023 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 <scmp/estimation/Madgwick.h>
#ifndef SCSL_ESTIMATION_H
#define SCSL_ESTIMATION_H
namespace scmp {
/// \brief Algorithms for estimation position, and system state.
namespace estimation {}
}
#endif // SCSL_ESTIMATION_H

View File

@ -1,8 +1,8 @@
///
/// \file include/scmp/filter/Madgwick.h
/// \file include/scmp/estimation/Madgwick.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2019-08-06
/// \brief Implementation of a Madgwick filter.
/// \brief Implementation of a Madgwick estimation.
///
/// See https://courses.cs.washington.edu/courses/cse466/14au/labs/l4/madgwick_internal_report.pdf.
///
@ -33,29 +33,29 @@
/// scmp contains the chimmering clarity math and physics code.
namespace scmp {
/// filter contains filtering algorithms.
namespace filter {
namespace estimation {
/// @brief Madgwick implements an efficient Orientation filter for IMUs.
/// \brief Madgwick implements an efficient Orientation estimation for
/// Intertial Measurement Units (IMUs).
///
/// Madgwick is a novel Orientation filter applicable to IMUs
/// Madgwick is a novel Orientation estimation applicable to IMUs
/// consisting of tri-Axis gyroscopes and accelerometers, and MARG
/// sensor arrays that also include tri-Axis magnetometers. The MARG
/// implementation incorporates magnetic distortionand gyroscope bias
/// drift compensation.
///
/// It is described in the paper [An efficient Orientation filter for inertial and inertial/magnetic sensor arrays](http://x-io.co.uk/res/doc/madgwick_internal_report.pdf).
/// It is described in the paper [An efficient Orientation estimation for inertial and inertial/magnetic sensor arrays](http://x-io.co.uk/res/doc/madgwick_internal_report.pdf).
///
/// \tparam T A floating point type.
template <typename T>
class Madgwick {
public:
/// \brief The Madgwick filter is initialised with an identity MakeQuaternion.
/// \brief The Madgwick estimation is initialised with an identity MakeQuaternion.
Madgwick() : deltaT(0.0), previousSensorFrame(), sensorFrame()
{};
/// \brief The Madgwick filter is initialised with a sensor frame.
/// \brief The Madgwick estimation is initialised with a sensor frame.
///
/// \param sf A sensor frame; if zero, the sensor frame will be
/// initialised as an identity MakeQuaternion.
@ -66,7 +66,7 @@ public:
}
}
/// \brief Initialise the filter with a sensor frame MakeQuaternion.
/// \brief Initialise the estimation with a sensor frame MakeQuaternion.
///
/// \param sf A MakeQuaternion representing the current Orientation.
Madgwick(scmp::geom::Quaternion<T> sf) :
@ -74,7 +74,7 @@ public:
{};
/// \brief Return the current orientation as measured by the
/// filter.
/// estimation.
///
/// \return The current sensor frame.
scmp::geom::Quaternion<T>
@ -83,15 +83,16 @@ public:
return this->sensorFrame;
}
/// \brief Return the filter's rate of angular change from a
/// \brief Return the estimation's rate of angular change from a
/// sensor frame.
///
/// Return the rate of change of the Orientation of the earth frame
/// with respect to the sensor frame.
/// Return the rate of change of the Orientation of the earth
/// frame with respect to the sensor frame.
///
/// \param gyro A three-dimensional vector containing gyro readings
/// as w_x, w_y, w_z.
/// \return A MakeQuaternion representing the rate of angular change.
/// \param gyro A three-dimensional vector containing gyro
/// readings as w_x, w_y, w_z.
/// \return A MakeQuaternion representing the rate of angular
/// change.
scmp::geom::Quaternion<T>
AngularRate(const scmp::geom::Vector<T, 3> &gyro) const
{
@ -112,8 +113,8 @@ public:
/// \brief Update the sensor frame to a new frame.
///
/// \warning The filter's default Δt must be set before calling
// this.
/// \warning The estimation's default Δt must be set before
/// calling this.
///
/// \param sf The new sensor frame replacing the previous one.
void
@ -129,9 +130,10 @@ public:
/// the compile flag NDEBUG, but may be useful to catch
/// possible errors.
///
/// \param gyro A three-dimensional vector containing gyro readings
/// as w_x, w_y, w_z.
/// \param delta The time step between readings. It must not be zero.
/// \param gyro A three-dimensional vector containing gyro
/// readings as w_x, w_y, w_z.
/// \param delta The time step between readings. It must not
/// be zero.
void
UpdateAngularOrientation(const scmp::geom::Vector<T, 3> &gyro, T delta)
{
@ -147,20 +149,21 @@ public:
/// \brief Update the sensor frame with a gyroscope reading.
///
/// If no Δt is provided, the filter's default is used.
/// If no Δt is provided, the estimation's default is used.
///
/// \warning The default Δt must be explicitly set using DeltaT
/// before calling this.
///
/// \param gyro A three-dimensional vector containing gyro readings
/// as w_x, w_y, w_z.
/// \param gyro A three-dimensional vector containing gyro
/// readings as w_x, w_y, w_z.
void
UpdateAngularOrientation(const scmp::geom::Vector<T, 3> &gyro)
{
this->UpdateAngularOrientation(gyro, this->deltaT);
}
/// \brief Retrieve a vector of the Euler angles in ZYX Orientation.
/// \brief Retrieve a vector of the Euler angles in ZYX
/// Orientation.
///
/// \return A vector of Euler angles as <ψ, θ, ϕ>.
scmp::geom::Vector<T, 3>
@ -172,19 +175,19 @@ public:
/// \brief Set the default Δt.
///
/// \note This must be explicitly called before calling any
/// method which uses the filter's internal Δt.
/// method which uses the estimation's internal Δt.
///
/// \param newDeltaT The time delta to use when no time delta is
/// provided.
/// \param newDeltaT The time delta to use when no time delta
/// is provided.
void
DeltaT(T newDeltaT)
{
this->deltaT = newDeltaT;
}
/// \brief Retrieve the filter's current ΔT.
/// \brief Retrieve the estimation's current ΔT.
///
/// \return The current value the filter will default to using
/// \return The current value the estimation will default to using
/// if no time delta is provided.
T DeltaT() { return this->deltaT; }
@ -202,7 +205,7 @@ using Madgwickd = Madgwick<double>;
using Madgwickf = Madgwick<float>;
} // namespace filter
} // namespace estimation
} // namespace scmp

View File

@ -91,19 +91,19 @@ float Heading2F(Vector2F vec);
///
/// \param vec A vector Orientation.
/// \return The compass heading of the vector in radians.
double Heading2d(Vector2D vec);
double Heading2D(Vector2D vec);
/// \brief Compass heading for a Vector2F.
///
/// \param vec A vector Orientation.
/// \return The compass heading of the vector in radians.
float Heading3f(Vector3F vec);
float Heading3F(Vector3F vec);
/// Heading3d returns a compass heading for a Vector2F.
/// 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);
double Heading3D(Vector3D vec);
} // namespace geom

View File

@ -61,7 +61,7 @@ enum class ArenaType
};
/// Arena is the class that implements a memory arena.
/// \brief Fixed, pre-allocated memory.
///
/// The Arena uses the concept of a cursor to point to memory in the arena. The
/// #Start and #End methods return pointers to the start and end of the

View File

@ -1,5 +1,5 @@
///
/// \file Buffer.h
/// \file include/scsl/Buffer.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-09
/// \brief Buffer implements basic line buffers.
@ -33,7 +33,7 @@
namespace scsl {
/// Buffer is a basic line buffer.
/// \brief Basic line buffer.
///
/// The buffer manages its own internal memory, growing and shrinking
/// as needed. Its capacity is separate from its length; the optimal

View File

@ -1,5 +1,5 @@
///
/// \file Commander.h
/// \file include/scsl/Commander.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-10
/// \brief Subprogram tooling.
@ -47,6 +47,8 @@ namespace scsl {
using CommanderFunc = std::function<bool (int, char **)>;
/// \brief Subcommands used by Commander.
///
/// Subcommands are the individual commands for the program. A Subcommand
/// will check that it has enough arguments before running its function.
class Subcommand {
@ -89,6 +91,8 @@ private:
std::string command;
};
/// \brief Subcommander manager for programs.
///
/// Commander collects subcommands and can run the apppropriate one.
///
/// For example:

View File

@ -1,5 +1,5 @@
///
/// \file Dictionary.h
/// \file include/scsl/Dictionary.h
/// \author kyle (kyle@imap.cc)
/// \date 2023-10-12
/// \brief Key-value store built on top of Arena and TLV.
@ -39,11 +39,7 @@ static constexpr uint8_t DICTIONARY_TAG_VAL = 2;
namespace scsl {
/*
* A Dictionary is a collection of key-value pairs, similar to how
* a dictionary is a mapping of names to definitions.
*/
/// Dictionary implements a key-value store on top of Arena and TLV::Record.
/// \brief Key-value store on top of Arena and TLV::Record.
///
/// Keys and vales are stored as sequential pairs of TLV records; they are
/// expected to contain string values but this isn't necessarily the case. The

View File

@ -55,7 +55,7 @@ typedef union {
} FlagValue;
/// Flag describes an individual command-line flag.
/// \brief Individual command-line flag
typedef struct {
FlagType Type; ///< The type of the value in the flag.
bool WasSet; ///< The flag was set on the command-line.
@ -64,7 +64,7 @@ typedef struct {
FlagValue Value; ///< The flag's value.
} Flag;
/// NewFlag is a helper function for constructing a new flag.
/// \brief NewFlag is a helper function for constructing a new flag.
///
/// \param fName The name of the flag.
/// \param fType The type of the flag.
@ -72,7 +72,7 @@ typedef struct {
/// \return A pointer to a flag.
Flag *NewFlag(std::string fName, FlagType fType, std::string fDescription);
/// Flags provides a basic facility for processing command line flags.
/// \brief Basic facility for processing command line flags.
///
/// Any remaining arguments after the args are added to the parser as
/// arguments that can be accessed with NumArgs, Args, and Arg.

View File

@ -1,5 +1,5 @@
///
/// \file StringUtil.h
/// \file include/scsl/StringUtil.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-14
/// \brief Utilities for working with strings.
@ -32,11 +32,8 @@
namespace scsl {
/// namespace U contains utilities.
namespace U {
/// namespace S contains string-related functions.
namespace S {
/// String-related utility functions.
namespace string {
/// Remove any whitespace At the beginning of the string. The string
@ -125,8 +122,7 @@ std::ostream &VectorToString(std::ostream &os, const std::vector<std::string> &s
std::string VectorToString(const std::vector<std::string> &svec);
} // namespace S
} // namespace U
} // namespace string
} // namespace scsl

View File

@ -1,5 +1,5 @@
///
/// \file TLV.h
/// \file include/scsl/TLV.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-06
/// \brief TLV.h implements basic tag-length-value records.
@ -21,6 +21,8 @@
namespace scsl {
/// \brief Tag-length-value record tooling
namespace TLV {
@ -31,7 +33,7 @@ static constexpr size_t TLV_MAX_LEN = 253;
static constexpr uint8_t TAG_EMPTY = 0;
/// Record describes a tag-length-value record.
/// \brief Tag-length-value record with single byte tags and lengths.
///
/// TLV records occupy a fixed size in memory, which can be controlled with the
/// TLV_MAX_LEN define. If this isn't defined, it defaults to a size of 253.

View File

@ -1,5 +1,5 @@
///
/// \file Exceptions.h
/// \file include/sctest/Exceptions.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-10
/// \brief Custom exceptions for use in SCSL used in writing test programs.
@ -31,7 +31,7 @@
namespace sctest {
/// NotImplemented is an exception reserved for unsupported platforms.
/// \brief Exception reserved for unsupported platforms.
///
/// It is used to mark functionality included for compatibility, and useful for
/// debugging.

View File

@ -1,26 +1,25 @@
//
// 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.
///
/// \file include/sctest/Report.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2017-06-05
/// \brief Unit test reporting class.
///
/// 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.
///
#ifndef SCTEST_REPORT_H
#define SCTEST_REPORT_H
@ -28,9 +27,15 @@
namespace sctest {
/// \brief A Report holds test run results.
///
/// This is designed to work with SimpleSuite, but might be useful
/// for other things.
class Report {
public:
/// \brief Construct a new Report, zeroed out.
Report();
/// \brief Failing returns the count of failed tests.
///
/// \details If a test is run and expected to pass, but fails,
@ -40,24 +45,48 @@ public:
/// \return The number of tests that failed.
size_t Failing() const;
/// \brief Returns the number of tests that have passed
/// successfully.
/// \brief The number of tests that have passed successfully.
size_t Passing() const;
/// \brief Total is the number of tests registered.
/// \brief The number of tests registered.
size_t Total() const;
/// \brief Report a test as having failed.
void Failed();
/// \brief Report a test as having passed.
void Passed();
/// \brief Register more tests in the report.
///
/// This is used to track the total number of tests in the
/// report.
void AddTest(size_t testCount = 0);
/// \brief Reset the internal state.
///
/// All fields in the Report will be zeroed out.
///
/// \param testCount
void Reset(size_t testCount = 0);
/// \brief Mark the start of test runs.
///
/// This is used for tracking how long the tests took to complete.
void Start();
/// \brief Mark the end of test runs.
///
/// This is used for tracking how long the tests took to complete.
void End();
/// \brief Retrieve how long the tests took to run.
///
/// This only makes sense to run after called to Start and End.
///
/// \return The number of milliseconds that have elapsed.
std::chrono::duration<double, std::milli>
Elapsed() const;
Report();
private:
size_t failing;
size_t passed;

View File

@ -1,5 +1,5 @@
///
/// \file SimpleSuite.h
/// \file include/sctest/SimpleSuite.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2017-06-05
/// \brief Defines a simple unit testing framework.
@ -33,8 +33,9 @@
namespace sctest {
/// \brief UnitTest describes a single unit test. It is a predicate:
/// did the test pass?
/// \brief UnitTest describes a single unit test.
///
/// It is a predicate: did the test pass?
struct UnitTest {
/// What name should be shown when running tests?
std::string name;
@ -99,12 +100,13 @@ public:
/// resetting the suite's internal state.
void Reset();
/// \brief
// HasRun returns true if a report is ready.
/// \brief Returns true if Run has been called.
bool HasRun() const;
// Report returns a Report.
Report GetReport(void);
/// \brief Retrieve the test run results.
///
/// The results will only be valid if Run has been called.
Report GetReport();
private:
bool quiet;

37
include/sctest/sctest.h Normal file
View File

@ -0,0 +1,37 @@
///
/// \file include/sctest/sctest.h
/// \author K. Isom <kyle@imap.cc>
/// \date 2023-10-20
/// \brief Shimmering Clarity testing code.
///
/// Copyright 2023 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 <sctest/Assert.h>
#include <sctest/Checks.h>
#include <sctest/Debug.h>
#include <sctest/Exceptions.h>
#include <sctest/Report.h>
#include <sctest/SimpleSuite.h>
#ifndef SCSL_SCTEST_H
#define SCSL_SCTEST_H
/// \brief Shimmering Clarity testing library.
namespace sctest {}
#endif // SCSL_SCTEST_H

View File

@ -30,11 +30,6 @@
#include <scmp/geom/Vector.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 scmp {
namespace geom {
@ -60,7 +55,7 @@ Point2D::Point2D(const Polar2D &pol)
int
Point2D::X() const
{
return this->At(0);
return this->At(BasisX);
}
@ -74,21 +69,21 @@ Point2D::X(int _x)
int
Point2D::Y() const
{
return this->At(1);
return this->At(BasisY);
}
void
Point2D::Y(int _y)
{
this->Set(1, _y);
this->Set(BasisY, _y);
}
std::ostream &
operator<<(std::ostream &outs, const Point2D &pt)
{
outs << "(" << std::to_string(pt[0]) << ", " << std::to_string(pt[1]) << ")";
outs << "(" << std::to_string(pt.X()) << ", " << std::to_string(pt.Y()) << ")";
return outs;
}
@ -192,8 +187,8 @@ Polar2D::Theta(const double _theta)
void
Polar2D::ToPoint(Point2D &point)
{
point.Y(std::rint(std::sin(this->Theta()) * this->R()));
point.X(std::rint(std::cos(this->Theta()) * this->R()));
point.Y(static_cast<int>(std::rint(std::sin(this->Theta()) * this->R())));
point.X(static_cast<int>(std::rint(std::cos(this->Theta()) * this->R())));
}
@ -232,4 +227,4 @@ operator<<(std::ostream &outs, const Polar2D &pol)
} // end namespace geom
} // end namespace math
} // end namespace scmp

View File

@ -1,19 +0,0 @@
#include <cmath>
#include <scmp/Motion2D.h>
namespace scmp {
namespace basic {
scmp::geom::Vector2D
Acceleration(double speed, double heading)
{
auto dx = std::cos(heading) * speed;
auto dy = std::sin(heading) * speed;
return scmp::geom::Vector2D({dx, dy});
}
} // namespace basic
} // namespace phys

View File

@ -1,3 +1,26 @@
///
/// \file src/scmp/geom/Orientation.cc
/// \author K. Isom <kyle@imap.cc>
/// \date 2017-06-05
/// \brief Orientation of vectors w.r.t. a reference plane, assumed to
/// be the Earth.
///
/// 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 <scmp/geom/Vector.h>
#include <scmp/geom/Orientation.h>
@ -14,25 +37,25 @@ Heading2F(Vector2F vec)
float
Heading3f(Vector3F vec)
Heading3F(Vector3F vec)
{
Vector2F vec2f {vec[0], vec[1]};
const Vector2F vec2f {vec.At(BasisX), vec.At(BasisY)};
return Heading2F(vec2f);
}
double
Heading2d(Vector2D vec)
Heading2D(Vector2D vec)
{
return vec.Angle(Basis2D[BasisX]);
}
double
Heading3d(Vector3D vec)
Heading3D(Vector3D vec)
{
Vector2D vec2d {vec[0], vec[1]};
return Heading2d(vec2d);
const Vector2D vec2d {vec.At(BasisX), vec.At(BasisY)};
return Heading2D(vec2d);
}

View File

@ -58,7 +58,7 @@ Flags::ParseStatusToString(ParseStatus status)
Flag *
NewFlag(std::string fName, FlagType fType, std::string fDescription)
{
auto flag = new Flag;
auto *flag = new Flag;
flag->Type = fType;
flag->WasSet = false;
@ -71,9 +71,8 @@ NewFlag(std::string fName, FlagType fType, std::string fDescription)
Flags::Flags(std::string fName)
: name(std::move(fName)), description("")
{
}
: name(std::move(fName))
{}
Flags::Flags(std::string fName, std::string fDescription)
@ -104,7 +103,7 @@ Flags::Register(std::string fName, FlagType fType, std::string fDescription)
return false;
}
auto flag = NewFlag(fName, fType, std::move(fDescription));
auto *flag = NewFlag(fName, fType, std::move(fDescription));
assert(flag != nullptr);
this->flags[fName] = flag;
return true;
@ -194,7 +193,7 @@ Flags::Lookup(std::string fName)
bool
Flags::ValueOf(std::string fName, FlagValue &value)
{
if (this->flags.count(fName)) {
if (this->flags.count(fName) != 0U) {
return false;
}
@ -207,7 +206,7 @@ Flags::ParseStatus
Flags::parseArg(int argc, char **argv, int &index)
{
std::string arg(argv[index]);
U::S::TrimWhitespace(arg);
string::TrimWhitespace(arg);
index++;
if (!std::regex_search(arg, isFlag)) {
@ -221,7 +220,7 @@ Flags::parseArg(int argc, char **argv, int &index)
return ParseStatus::NotRegistered;
}
auto flag = flags[arg];
auto *flag = flags[arg];
if ((flag->Type != FlagType::Boolean) && index == argc) {
return ParseStatus::NotEnoughArgs;
}
@ -233,11 +232,11 @@ Flags::parseArg(int argc, char **argv, int &index)
return ParseStatus::OK;
case FlagType::Integer:
flag->WasSet = true;
flag->Value.i = std::stoi(argv[++index], 0, 0);
flag->Value.i = std::stoi(argv[++index], nullptr, 0);
return ParseStatus::OK;
case FlagType::UnsignedInteger:
flag->WasSet = true;
flag->Value.u = static_cast<unsigned int>(std::stoi(argv[index++], 0, 0));
flag->Value.u = static_cast<unsigned int>(std::stoi(argv[index++], nullptr, 0));
return ParseStatus::OK;
case FlagType::String:
flag->WasSet = true;
@ -275,7 +274,7 @@ Flags::Parse(int argc, char **argv, bool skipFirst)
case ParseStatus::EndOfFlags:
while (index < argc) {
this->args.push_back(std::string(argv[index]));
this->args.emplace_back(argv[index]);
index++;
}
continue;
@ -303,7 +302,7 @@ Flags::Usage(std::ostream &os, int exitCode)
os << this->name << ":\t";
auto indent = this->name.size() + 7;
U::S::WriteTabIndented(os, description, 72 - indent, indent / 8, false);
string::WriteTabIndented(os, description, 72 - indent, indent / 8, false);
os << "\n\n";
for (const auto &pair : this->flags) {
@ -337,7 +336,7 @@ Flags::Usage(std::ostream &os, int exitCode)
os << argLine;
indent = argLine.size();
U::S::WriteTabIndented(os, pair.second->Description,
string::WriteTabIndented(os, pair.second->Description,
72-indent, (indent/8)+2, false);
}
@ -374,11 +373,11 @@ Flags::Arg(size_t i)
Flag *
Flags::checkGetArg(std::string& fName, FlagType eType)
{
if (this->flags[fName] == 0) {
if (this->flags[fName] == nullptr) {
return nullptr;
}
auto flag = this->flags[fName];
auto *flag = this->flags[fName];
if (flag == nullptr) {
return nullptr;
}
@ -394,7 +393,7 @@ Flags::checkGetArg(std::string& fName, FlagType eType)
bool
Flags::GetBool(std::string fName, bool &flagValue)
{
auto flag = this->checkGetArg(fName, FlagType::Boolean);
auto *flag = this->checkGetArg(fName, FlagType::Boolean);
flagValue = flag->Value.b;
return flag->WasSet;
@ -404,7 +403,7 @@ Flags::GetBool(std::string fName, bool &flagValue)
bool
Flags::GetInteger(std::string fName, int &flagValue)
{
auto flag = this->checkGetArg(fName, FlagType::Integer);
auto *flag = this->checkGetArg(fName, FlagType::Integer);
flagValue = flag->Value.i;
return flag->WasSet;
@ -414,7 +413,7 @@ Flags::GetInteger(std::string fName, int &flagValue)
bool
Flags::GetUnsignedInteger(std::string fName, unsigned int &flagValue)
{
auto flag = this->checkGetArg(fName, FlagType::UnsignedInteger);
auto *flag = this->checkGetArg(fName, FlagType::UnsignedInteger);
flagValue = flag->Value.u;
return flag->WasSet;
@ -424,7 +423,7 @@ Flags::GetUnsignedInteger(std::string fName, unsigned int &flagValue)
bool
Flags::GetSizeT(std::string fName, std::size_t &flagValue)
{
auto flag = this->checkGetArg(fName, FlagType::SizeT);
auto *flag = this->checkGetArg(fName, FlagType::SizeT);
flagValue = flag->Value.size;
return flag->WasSet;
@ -434,7 +433,7 @@ Flags::GetSizeT(std::string fName, std::size_t &flagValue)
bool
Flags::GetString(std::string fName, std::string &flagValue)
{
auto flag = this->checkGetArg(fName, FlagType::String);
auto *flag = this->checkGetArg(fName, FlagType::String);
if (flag->Value.s == nullptr) {
return false;

View File

@ -28,11 +28,7 @@
namespace scsl {
/// namespace U contains utilities.
namespace U {
/// namespace S contains string-related functions.
namespace S {
namespace string {
std::vector<std::string>
@ -40,9 +36,11 @@ SplitKeyValuePair(std::string line, std::string delimiter)
{
auto pair = SplitN(std::move(line), std::move(delimiter), 2);
if (pair.size() == 0) {
if (pair.empty()) {
return {"", ""};
} else if (pair.size() == 1) {
}
if (pair.size() == 1) {
return {pair[0], ""};
}
@ -61,7 +59,7 @@ SplitKeyValuePair(std::string line, char delimiter)
{
std::string sDelim;
sDelim.push_back(std::move(delimiter));
sDelim.push_back(delimiter);
return SplitKeyValuePair(std::move(line), sDelim);
}
@ -72,7 +70,7 @@ TrimLeadingWhitespace(std::string &s)
s.erase(s.begin(),
std::find_if(s.begin(), s.end(),
[](unsigned char ch) {
return !std::isspace(ch);
return std::isspace(ch) == 0;
}));
}
@ -81,7 +79,7 @@ void
TrimTrailingWhitespace(std::string &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
return std::isspace(ch) == 0;
}).base(), s.end());
}
@ -125,9 +123,9 @@ SplitN(std::string s, std::string delim, size_t maxCount)
size_t ss = 0;
size_t se = 0;
for (ss = 0; s.size() != 0 && ss < s.size(); ss++) {
for (ss = 0; !s.empty() && ss < s.size(); ss++) {
se = s.find(delim, ss);
if ((maxCount > 0) && (parts.size() == maxCount - 1)) {
if ((maxCount > 0) && (parts.size() == (maxCount - 1))) {
se = s.size();
} else if (se == std::string::npos) {
se = s.size();
@ -155,7 +153,7 @@ WrapText(std::string& line, size_t lineLength)
std::string wLine;
for (auto &word: parts) {
if (word.size() == 0) {
if (word.empty()) {
continue;
}
@ -164,13 +162,13 @@ WrapText(std::string& line, size_t lineLength)
wLine.clear();
}
if (wLine.size() > 0) {
if (!wLine.empty()) {
wLine += " ";
}
wLine += word;
}
if (wLine.size() > 0) {
if (!wLine.empty()) {
wrapped.push_back(wLine);
}
@ -182,7 +180,7 @@ void
WriteTabIndented(std::ostream &os, std::vector<std::string> lines,
int tabStop, bool indentFirst)
{
std::string indent(tabStop, '\t');
std::string const indent(tabStop, '\t');
for (size_t i = 0; i < lines.size(); i++) {
if (i > 0 || indentFirst) {
@ -230,6 +228,5 @@ VectorToString(const std::vector<std::string> &svec)
}
} // namespace S
} // namespace U
} // namespace string
} // namespace scsl

View File

@ -7,7 +7,7 @@
#include <scmp/geom/Quaternion.h>
#include <scmp/Math.h>
#include <scmp/filter/Madgwick.h>
#include <scmp/estimation/Madgwick.h>
#include <sctest/Assert.h>
#include <sctest/Checks.h>
#include <sctest/SimpleSuite.h>
@ -20,22 +20,22 @@ using namespace scmp;
bool
SimpleAngularOrientationFloat()
{
filter::Madgwickf mflt;
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
estimation::Madgwickf estimation;
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaternionf frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const float delta = 0.00917; // assume 109 updates per second, as per the paper.
const float twentyDegrees = scmp::DegreesToRadiansF(20.0);
const float delta = 0.00917; // assume 109 updates per second, as per the paper.
const float twentyDegrees = scmp::DegreesToRadiansF(20.0);
// The paper specifies a minimum of 109 IMU readings to stabilize; for
// two seconds, that means 218 updates.
for (int i = 0; i < 218; i++) {
mflt.UpdateAngularOrientation(gyro, delta);
estimation.UpdateAngularOrientation(gyro, delta);
}
SCTEST_CHECK_EQ(mflt.Orientation(), frame20Deg);
SCTEST_CHECK_EQ(estimation.Orientation(), frame20Deg);
auto euler = mflt.Euler();
auto euler = estimation.Euler();
SCTEST_CHECK_FEQ_EPS(euler[0], twentyDegrees, 0.01);
SCTEST_CHECK_FEQ_EPS(euler[1], 0.0, 0.01);
SCTEST_CHECK_FEQ_EPS(euler[2], 0.0, 0.01);
@ -47,7 +47,7 @@ SimpleAngularOrientationFloat()
bool
SimpleAngularOrientationFloatDefaultDT()
{
filter::Madgwickf mflt;
estimation::Madgwickf mflt;
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaternionf frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const float delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -75,7 +75,7 @@ SimpleAngularOrientationFloatDefaultDT()
bool
VerifyUpdateWithZeroDeltaTFails()
{
filter::Madgwickf mflt;
estimation::Madgwickf mflt;
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaternionf frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const float twentyDegrees = scmp::DegreesToRadiansF(20.0);
@ -100,7 +100,7 @@ VerifyUpdateWithZeroDeltaTFails()
bool
SimpleAngularOrientationDouble()
{
filter::Madgwickd mflt;
estimation::Madgwickd mflt;
const geom::Vector3D gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaterniond frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const double delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -127,7 +127,7 @@ bool
SimpleAngularOrientation2InitialVector3f()
{
const geom::Vector3F initialFrame{0, 0, 0};
filter::Madgwickf mflt(initialFrame);
estimation::Madgwickf mflt(initialFrame);
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaternionf frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const float delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -154,7 +154,7 @@ bool
SimpleAngularOrientation2InitialQuaternionf()
{
const auto initialFrame = geom::FloatQuaternionFromEuler({0, 0, 0});
filter::Madgwickf mflt(initialFrame);
estimation::Madgwickf mflt(initialFrame);
const geom::Vector3F gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaternionf frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const float delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -181,7 +181,7 @@ bool
SimpleAngularOrientation2InitialVector3d()
{
const geom::Vector3D initialFrame{0, 0, 0};
filter::Madgwickd mflt(initialFrame);
estimation::Madgwickd mflt(initialFrame);
const geom::Vector3D gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaterniond frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const double delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -208,7 +208,7 @@ bool
SimpleAngularOrientation2InitialQuaterniond()
{
const auto initialFrame = geom::DoubleQuaternionFromEuler({0, 0, 0});
filter::Madgwickd mflt(initialFrame);
estimation::Madgwickd mflt(initialFrame);
const geom::Vector3D gyro{0.174533, 0.0, 0.0}; // 10° X rotation.
const geom::Quaterniond frame20Deg{0.984808, 0.173648, 0, 0}; // 20° final Orientation.
const double delta = 0.00917; // assume 109 updates per second, as per the paper.
@ -236,8 +236,8 @@ main(int argc, char **argv)
{
auto quiet = false;
auto noReport = false;
auto flags = new scsl::Flags("test_madgwick",
"This test validates the Madgwick filter code");
auto *flags = new scsl::Flags("test_madgwick",
"This test validates the Madgwick estimation code");
flags->Register("-n", false, "don't print the report");
flags->Register("-q", false, "suppress test output");

View File

@ -45,7 +45,7 @@ UnitConversions_RadiansToDegreesD()
bool
Orientation2f_Heading()
{
geom::Vector2F a{2.0, 2.0};
geom::Vector2F const a{2.0, 2.0};
SCTEST_CHECK_FEQ(geom::Heading2F(a), scmp::DegreesToRadiansF(45));
@ -56,9 +56,9 @@ Orientation2f_Heading()
bool
Orientation3f_Heading()
{
geom::Vector3F a{2.0, 2.0, 2.0};
geom::Vector3F const a{2.0, 2.0, 2.0};
SCTEST_CHECK_FEQ(geom::Heading3f(a), scmp::DegreesToRadiansF(45));
SCTEST_CHECK_FEQ(geom::Heading3F(a), scmp::DegreesToRadiansF(45));
return true;
}
@ -67,18 +67,18 @@ Orientation3f_Heading()
bool
Orientation2d_Heading()
{
geom::Vector2D a{2.0, 2.0};
geom::Vector2D const a{2.0, 2.0};
return scmp::WithinTolerance(geom::Heading2d(a), scmp::DegreesToRadiansD(45), 0.000001);
return scmp::WithinTolerance(geom::Heading2D(a), scmp::DegreesToRadiansD(45), 0.000001) != 0.0;
}
bool
Orientation3d_Heading()
{
geom::Vector3D a{2.0, 2.0, 2.0};
geom::Vector3D const a{2.0, 2.0, 2.0};
return scmp::WithinTolerance(geom::Heading3d(a), scmp::DegreesToRadiansD(45), 0.000001);
return scmp::WithinTolerance(geom::Heading3D(a), scmp::DegreesToRadiansD(45), 0.000001) != 0.0;
}
@ -90,7 +90,7 @@ main(int argc, char *argv[])
{
auto noReport = false;
auto quiet = false;
auto flags = new scsl::Flags("test_orientation",
auto *flags = new scsl::Flags("test_orientation",
"This test validates various orientation-related components in scmp.");
flags->Register("-n", false, "don't print the report");
flags->Register("-q", false, "suppress test output");

View File

@ -42,30 +42,30 @@ TestTrimming(std::string line, std::string lExpected, std::string rExpected, std
std::string result;
std::string message;
result = U::S::TrimLeadingWhitespaceDup(line);
result = string::TrimLeadingWhitespaceDup(line);
message = "TrimLeadingDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == lExpected, message);
result = U::S::TrimTrailingWhitespaceDup(line);
result = string::TrimTrailingWhitespaceDup(line);
message = "TrimTrailingDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == rExpected, message);
result = U::S::TrimWhitespaceDup(line);
result = string::TrimWhitespaceDup(line);
message = "TrimDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == expected, message);
result = line;
U::S::TrimLeadingWhitespace(result);
string::TrimLeadingWhitespace(result);
message = "TrimLeadingDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == lExpected, message);
result = line;
U::S::TrimTrailingWhitespace(result);
string::TrimTrailingWhitespace(result);
message = "TrimTrailingDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == rExpected, message);
result = line;
U::S::TrimWhitespace(result);
string::TrimWhitespace(result);
message = "TrimDup(\"" + line + "\"): '" + result + "'";
sctest::Assert(result == expected, message);
}
@ -75,7 +75,7 @@ std::function<bool()>
TestSplit(std::string line, std::string delim, size_t maxCount, std::vector<std::string> expected)
{
return [line, delim, maxCount, expected]() {
return U::S::SplitN(line, delim, maxCount) == expected;
return string::SplitN(line, delim, maxCount) == expected;
};
}
@ -86,7 +86,7 @@ TestSplitChar()
{
auto expected = std::vector<std::string>{"hello", "world"};
const auto *inputLine = "hello=world\n";
auto actual = U::S::SplitKeyValuePair(inputLine, '=');
auto actual = string::SplitKeyValuePair(inputLine, '=');
return actual == expected;
}
@ -109,11 +109,11 @@ TestWrapping()
"hope so.",
};
auto wrapped = U::S::WrapText(testLine, 16);
auto wrapped = string::WrapText(testLine, 16);
if (wrapped.size() != expected.size()) {
std::cerr << U::S::VectorToString(wrapped)
std::cerr << string::VectorToString(wrapped)
<< " != "
<< U::S::VectorToString(expected)
<< string::VectorToString(expected)
<< "\n";
}
@ -127,7 +127,7 @@ TestWrapping()
return false;
}
// U::S::WriteTabIndented(std::cout, wrapped, 4, true);
// string::WriteTabIndented(std::cout, wrapped, 4, true);
return true;
}
@ -140,7 +140,7 @@ main(int argc, char *argv[])
{
auto noReport = false;
auto quiet = false;
auto flags = new scsl::Flags("test_orientation",
auto *flags = new scsl::Flags("test_orientation",
"This test validates various orientation-related components in scmp.");
flags->Register("-n", false, "don't print the report");
flags->Register("-q", false, "suppress test output");