-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from eggrobin/affine-spaces
Affine maps
- Loading branch information
Showing
12 changed files
with
395 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
#include "geometry/point.hpp" | ||
#include "geometry/grassmann.hpp" | ||
|
||
namespace principia { | ||
namespace geometry { | ||
|
||
template<typename FromFrame, typename ToFrame, typename Scalar, | ||
template<typename, typename> class LinearMap> | ||
class AffineMap { | ||
public: | ||
typedef Vector<Scalar, FromFrame> FromVector; | ||
typedef Vector<Scalar, ToFrame> ToVector; | ||
// The identity map. | ||
AffineMap() = default; | ||
AffineMap(Point<FromVector> const& from_origin, | ||
Point<ToVector> const& to_origin, | ||
LinearMap<FromFrame, ToFrame> const& linear_map); | ||
|
||
AffineMap<ToFrame, FromFrame, Scalar, LinearMap> Inverse() const; | ||
Point<ToVector> operator()(Point<FromVector> const& point) const; | ||
|
||
private: | ||
// The map is internally represented as x -> linear_map_(x) + translation_. | ||
ToVector translation_; | ||
LinearMap<FromFrame, ToFrame> linear_map_; | ||
|
||
template<typename FromFrame, typename ThroughFrame, typename ToFrame, | ||
typename Scalar, template<typename, typename> class LinearMap> | ||
friend AffineMap<FromFrame, ToFrame, Scalar, LinearMap> operator*( | ||
AffineMap<ThroughFrame, ToFrame, Scalar, LinearMap> const& left, | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap> const& right); | ||
}; | ||
|
||
template<typename FromFrame, typename ThroughFrame, typename ToFrame, | ||
typename Scalar, template<typename, typename> class LinearMap> | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap> operator*( | ||
AffineMap<ThroughFrame, ToFrame, Scalar, LinearMap> const& left, | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap> const& right); | ||
|
||
} // namespace geometry | ||
} // namespace principia | ||
|
||
#include "geometry/affine_map_body.hpp" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#pragma once | ||
|
||
#include "geometry/point.hpp" | ||
#include "geometry/grassmann.hpp" | ||
|
||
namespace principia { | ||
namespace geometry { | ||
|
||
// Since the map is represented as x -> linear_map_(x) + translation_ and since | ||
// it is x -> linear_map(x - from_origin) + to_origin, we get | ||
// linear_map_ = linear_map, translation_ = to_origin - linear_map(from_origin). | ||
template<typename FromFrame, typename ToFrame, typename Scalar, | ||
template<typename, typename> class LinearMap> | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap>::AffineMap( | ||
Point<FromVector> const& from_origin, | ||
Point<ToVector> const& to_origin, | ||
LinearMap<FromFrame, ToFrame> const& linear_map) | ||
: linear_map_(linear_map), | ||
translation_(to_origin.coordinates_ - | ||
linear_map(from_origin.coordinates_)) {} | ||
|
||
template<typename FromFrame, typename ToFrame, typename Scalar, | ||
template<typename, typename> class LinearMap> | ||
AffineMap<ToFrame, FromFrame, Scalar, LinearMap> | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap>::Inverse() const { | ||
AffineMap<ToFrame, FromFrame, Scalar, LinearMap> result; | ||
result.linear_map_ = linear_map_.Inverse(); | ||
result.translation_ = -result.linear_map_(translation_); | ||
return result; | ||
} | ||
|
||
template<typename FromFrame, typename ToFrame, typename Scalar, | ||
template<typename, typename> class LinearMap> | ||
Point<typename AffineMap<FromFrame, ToFrame, Scalar, LinearMap>::ToVector> | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap>::operator()( | ||
Point<FromVector> const& point) const { | ||
return Point< | ||
typename AffineMap<FromFrame, ToFrame, Scalar, LinearMap>::ToVector>( | ||
linear_map_(point.coordinates_) + translation_); | ||
} | ||
|
||
template<typename FromFrame, typename ThroughFrame, typename ToFrame, | ||
typename Scalar, template<typename, typename> class LinearMap> | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap> operator*( | ||
AffineMap<ThroughFrame, ToFrame, Scalar, LinearMap> const& left, | ||
AffineMap<FromFrame, ToFrame, Scalar, LinearMap> const& right) { | ||
AffineMap<ToFrame, FromFrame, Scalar, LinearMap> result; | ||
result.linear_map_ = left.linear_map_ * right.linear_map_; | ||
result.translation_ = left.linear_map_(right.translation_) + | ||
left.translation_; | ||
return result; | ||
} | ||
|
||
} // namespace geometry | ||
} // namespace principia |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
#include "geometry/affine_map.hpp" | ||
|
||
#include <cfloat> | ||
|
||
#include <vector> | ||
|
||
#include "geometry/grassmann.hpp" | ||
#include "geometry/orthogonal_map.hpp" | ||
#include "geometry/permutation.hpp" | ||
#include "geometry/point.hpp" | ||
#include "geometry/rotation.hpp" | ||
#include "gmock/gmock.h" | ||
#include "gtest/gtest.h" | ||
#include "quantities/numbers.hpp" | ||
#include "quantities/si.hpp" | ||
#include "testing_utilities/almost_equals.hpp" | ||
#include "testing_utilities/numerics.hpp" | ||
|
||
namespace principia { | ||
namespace geometry { | ||
|
||
using quantities::Length; | ||
using si::Metre; | ||
using si::Radian; | ||
using testing::Contains; | ||
using testing::Eq; | ||
using testing::Lt; | ||
using testing_utilities::AlmostEquals; | ||
using testing_utilities::RelativeError; | ||
|
||
class AffineMapTest : public testing::Test { | ||
protected: | ||
struct World; | ||
typedef OrthogonalMap<World, World> Orth; | ||
typedef Permutation<World, World> Perm; | ||
typedef Rotation<World, World> Rot; | ||
typedef Vector<Length, World> Displacement; | ||
typedef Point<Displacement> Position; | ||
typedef AffineMap<World, World, Length, Rotation> RigidTransformation; | ||
|
||
void SetUp() override { | ||
zero_ = Displacement({0 * Metre, 0 * Metre, 0 * Metre}); | ||
forward_ = Displacement({1 * Metre, 0 * Metre, 0 * Metre}); | ||
leftward_ = Displacement({0 * Metre, 1 * Metre, 0 * Metre}); | ||
upward_ = Displacement({0 * Metre, 0 * Metre, 1 * Metre}); | ||
|
||
origin_ = Position(Displacement({0 * Metre, 0 * Metre, 0 * Metre})); | ||
|
||
back_right_bottom_ = Position(Displacement({3 * Metre, | ||
4 * Metre, | ||
5 * Metre})); | ||
front_right_bottom_ = back_right_bottom_ + forward_; | ||
back_left_bottom_ = back_right_bottom_ + leftward_; | ||
front_left_bottom_ = back_left_bottom_ + forward_; | ||
back_right_top_ = back_right_bottom_ + upward_; | ||
front_right_top_ = back_right_top_ + forward_; | ||
back_left_top_ = back_right_top_ + leftward_; | ||
front_left_top_ = back_left_top_ + forward_; | ||
vertices_ = {back_left_bottom_, front_left_bottom_, back_right_bottom_, | ||
front_right_bottom_, back_left_top_, front_left_top_, | ||
back_right_top_, front_right_top_}; | ||
originated_vertices_ = std::vector<Displacement>(vertices_.size()); | ||
for (std::size_t i = 0; i < vertices_.size(); ++i) { | ||
originated_vertices_[i] = vertices_[i] - origin_; | ||
} | ||
} | ||
|
||
Vector<Length, World> zero_; | ||
Vector<Length, World> forward_; | ||
Vector<Length, World> leftward_; | ||
Vector<Length, World> upward_; | ||
Position origin_; | ||
Position back_left_bottom_; | ||
Position front_left_bottom_; | ||
Position back_right_bottom_; | ||
Position front_right_bottom_; | ||
Position back_left_top_; | ||
Position front_left_top_; | ||
Position back_right_top_; | ||
Position front_right_top_; | ||
std::vector<Position> vertices_; | ||
std::vector<Displacement> originated_vertices_; | ||
}; | ||
|
||
TEST_F(AffineMapTest, Cube) { | ||
Rot rotate_left(π / 2 * Radian, upward_); | ||
EXPECT_THAT(RelativeError(leftward_, rotate_left(forward_)), | ||
Lt(2 * DBL_EPSILON)); | ||
RigidTransformation map = RigidTransformation(back_right_bottom_, | ||
front_right_bottom_, | ||
rotate_left); | ||
EXPECT_THAT(map(back_right_bottom_) - origin_, | ||
Eq(front_right_bottom_ - origin_)); | ||
EXPECT_THAT(map(front_left_top_) - origin_, | ||
AlmostEquals(back_left_top_ - origin_)); | ||
// Check that |map| is an isometry of the cube whose vertices are |vertices_|. | ||
for (auto const& point : vertices_) { | ||
EXPECT_THAT(originated_vertices_, | ||
Contains(AlmostEquals(map(point) - origin_))); | ||
} | ||
// Test that |map.Inverse() * map| acts as the identity on that cube. | ||
for (std::size_t i = 0; i < vertices_.size(); ++i) { | ||
EXPECT_THAT(originated_vertices_[i], | ||
AlmostEquals((map.Inverse() * map)(vertices_[i]) - origin_)); | ||
} | ||
} | ||
|
||
} // namespace geometry | ||
} // namespace principia |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.