Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
transformation.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "core/rational.hpp"
4
18
19#include <array>
20#include <cmath>
21#include <concepts>
22#include <type_traits>
23
24namespace pgl {
25
31template <class Number>
34 using NumberType = Number;
35
39 constexpr Transformation() = default;
40
51 constexpr Transformation(Number a, Number b, Number c, Number d,
52 Number tx = Number{}, Number ty = Number{})
53 : m_{{{a, b, tx}, {c, d, ty}}} {}
54
61 template <class OtherNumber>
63 : m_{{
64 {static_cast<Number>(other.a()), static_cast<Number>(other.b()), static_cast<Number>(other.tx())},
65 {static_cast<Number>(other.c()), static_cast<Number>(other.d()), static_cast<Number>(other.ty())},
66 }} {}
67
71 static constexpr Transformation identity() {
72 return Transformation();
73 }
74
78 static constexpr Transformation translation(Number dx, Number dy) {
79 return Transformation(Number{1}, Number{}, Number{}, Number{1}, dx, dy);
80 }
81
88 static constexpr Transformation scaling(Number sx, Number sy) {
89 return Transformation(sx, Number{}, Number{}, sy);
90 }
91
97 static constexpr Transformation scaling(Number s) {
98 return scaling(s, s);
99 }
100
108 static constexpr Transformation rotation90(int k = 1) {
109 switch (((k % 4) + 4) % 4) {
110 case 1: return Transformation(Number{}, -Number{1}, Number{1}, Number{});
111 case 2: return Transformation(-Number{1}, Number{}, Number{}, -Number{1});
112 case 3: return Transformation(Number{}, Number{1}, -Number{1}, Number{});
113 default: return identity();
114 }
115 }
116
120 static constexpr Transformation shearX(Number k) {
121 return Transformation(Number{1}, k, Number{}, Number{1});
122 }
123
127 static constexpr Transformation shearY(Number k) {
128 return Transformation(Number{1}, Number{}, k, Number{1});
129 }
130
134 static constexpr Transformation reflectionX() {
135 return Transformation(Number{1}, Number{}, Number{}, -Number{1});
136 }
137
141 static constexpr Transformation reflectionY() {
142 return Transformation(-Number{1}, Number{}, Number{}, Number{1});
143 }
144
155 template <std::floating_point ResultNumber = double>
156 static Transformation<ResultNumber> rotation(ResultNumber radians) {
157 const ResultNumber cosine = std::cos(radians);
158 const ResultNumber sine = std::sin(radians);
159 return Transformation<ResultNumber>(cosine, -sine, sine, cosine);
160 }
161
163 constexpr Number a() const { return m_[0][0]; }
165 constexpr Number b() const { return m_[0][1]; }
167 constexpr Number c() const { return m_[1][0]; }
169 constexpr Number d() const { return m_[1][1]; }
171 constexpr Number tx() const { return m_[0][2]; }
173 constexpr Number ty() const { return m_[1][2]; }
174
182 constexpr auto determinant() const {
183 return a() * d() - b() * c();
184 }
185
191 constexpr bool isInvertible() const {
192 return determinant() != decltype(determinant()){};
193 }
194
203 template <class ResultNumber = division_result_t<NumberType>>
205 const ResultNumber det = static_cast<ResultNumber>(determinant());
206 const ResultNumber ra = static_cast<ResultNumber>(a());
207 const ResultNumber rb = static_cast<ResultNumber>(b());
208 const ResultNumber rc = static_cast<ResultNumber>(c());
209 const ResultNumber rd = static_cast<ResultNumber>(d());
210 const ResultNumber rtx = static_cast<ResultNumber>(tx());
211 const ResultNumber rty = static_cast<ResultNumber>(ty());
213 rd / det, -rb / det,
214 -rc / det, ra / det,
215 (rb * rty - rd * rtx) / det,
216 (rc * rtx - ra * rty) / det);
217 }
218
225 template <class OtherNumber>
226 constexpr auto operator*(const Transformation<OtherNumber>& other) const {
227 using ResultNumber = std::common_type_t<Number, OtherNumber>;
229 a() * other.a() + b() * other.c(),
230 a() * other.b() + b() * other.d(),
231 c() * other.a() + d() * other.c(),
232 c() * other.b() + d() * other.d(),
233 a() * other.tx() + b() * other.ty() + tx(),
234 c() * other.tx() + d() * other.ty() + ty());
235 }
236
240 constexpr bool operator==(const Transformation&) const = default;
241
242 private:
243 std::array<std::array<Number, 3>, 2> m_{{{Number{1}, Number{}, Number{}}, {Number{}, Number{1}, Number{}}}};
244};
245
260template <class Number, class ShapeT>
261 requires (detail::shapeRank<ShapeT> >= 0 && !RectangleConcept<ShapeT> && !DiskConcept<ShapeT>)
262[[nodiscard]] constexpr auto operator*(const Transformation<Number>& transformation, const ShapeT& shape);
263
269template <class Number, ShapeConcept ShapeT>
270[[nodiscard]] constexpr auto operator*(const Transformation<Number>& transformation, const ShapeT& shape);
271
272} // namespace pgl
Definition arrangement.hpp:67
Exact rational number type used when geometric results need fractions.
static constexpr Transformation scaling(Number sx, Number sy)
Returns a non-uniform scaling around the origin.
Definition transformation.hpp:88
static constexpr Transformation translation(Number dx, Number dy)
Returns a translation by (dx, dy).
Definition transformation.hpp:78
constexpr Transformation< ResultNumber > inverse() const
Returns the inverse transformation.
Definition transformation.hpp:204
constexpr Number ty() const
Returns the translation added to the second coordinate.
Definition transformation.hpp:173
constexpr bool operator==(const Transformation &) const =default
Compares the matrix entries for equality.
constexpr ERational a() const
Definition transformation.hpp:163
constexpr ERational d() const
Definition transformation.hpp:169
static constexpr Transformation reflectionY()
Returns a reflection across the y-axis.
Definition transformation.hpp:141
Number NumberType
Definition transformation.hpp:34
constexpr Transformation()=default
Creates the identity transformation.
constexpr auto determinant() const
Returns the determinant of the linear (non-translation) part.
Definition transformation.hpp:182
constexpr Transformation(const Transformation< OtherNumber > &other)
Converts a transformation with a different entry type.
Definition transformation.hpp:62
constexpr ERational tx() const
Definition transformation.hpp:171
static constexpr Transformation shearY(Number k)
Returns a vertical shear: (x, y) -> (x, y + k*x).
Definition transformation.hpp:127
constexpr ERational c() const
Definition transformation.hpp:167
static Transformation< ResultNumber > rotation(ResultNumber radians)
Returns a rotation around the origin by an arbitrary angle.
Definition transformation.hpp:156
static constexpr Transformation shearX(Number k)
Returns a horizontal shear: (x, y) -> (x + k*y, y).
Definition transformation.hpp:120
static constexpr Transformation rotation90(int k=1)
Returns a rotation around the origin by 90k degrees.
Definition transformation.hpp:108
static constexpr Transformation scaling(Number s)
Returns a uniform scaling around the origin.
Definition transformation.hpp:97
constexpr auto operator*(const Transformation< OtherNumber > &other) const
Composes two transformations: (*this) * other applies other first, then *this.
Definition transformation.hpp:226
static constexpr Transformation reflectionX()
Returns a reflection across the x-axis.
Definition transformation.hpp:134
constexpr ERational b() const
Definition transformation.hpp:165
static constexpr Transformation identity()
Returns the identity transformation.
Definition transformation.hpp:71
constexpr Transformation(Number a, Number b, Number c, Number d, Number tx=Number{}, Number ty=Number{})
Creates a transformation from its matrix entries.
Definition transformation.hpp:51
constexpr bool isInvertible() const
Tests whether the transformation has an inverse.
Definition transformation.hpp:191