From 26f08a00606633d2737808664e443c323844104d Mon Sep 17 00:00:00 2001 From: Wai-Shing Luk Date: Wed, 21 Jul 2021 22:50:43 +0800 Subject: [PATCH] fix github action; remove macos build; style change --- .github/workflows/documentation.yaml | 12 +- .github/workflows/{macos.yml => macos.old} | 0 .github/workflows/style.yml | 13 +- .github/workflows/windows.yml | 2 +- include/projgeom/ck_plane.hpp | 496 +++++------ include/projgeom/common_concepts.h | 99 +-- include/projgeom/euclid_plane.hpp | 362 ++++---- include/projgeom/euclid_plane_measure.hpp | 299 +++---- include/projgeom/fractions.hpp | 966 ++++++++++----------- include/projgeom/fractions_gcd.hpp | 938 +++++++++----------- include/projgeom/persp_plane.hpp | 310 ++++--- include/projgeom/pg_common.hpp | 238 +++-- include/projgeom/pg_line.hpp | 76 +- include/projgeom/pg_object.hpp | 285 +++--- include/projgeom/pg_point.hpp | 120 ++- include/projgeom/proj_plane.hpp | 449 +++++----- include/projgeom/proj_plane_concepts.h | 302 ++++--- include/projgeom/proj_plane_measure.hpp | 200 ++--- standalone/CMakeLists.txt | 4 +- standalone/source/main.cpp | 4 +- test/CMakeLists.txt | 2 +- test/source/test_ck_plane.cpp | 83 +- test/source/test_concepts.cpp | 74 +- test/source/test_ell_plane.cpp | 43 +- test/source/test_euclid.cpp | 75 +- test/source/test_frac.cpp | 45 +- test/source/test_persp_plane.cpp | 52 +- test/source/test_proj_plane.cpp | 33 +- 28 files changed, 2548 insertions(+), 3034 deletions(-) rename .github/workflows/{macos.yml => macos.old} (100%) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 13e23dd..271ad3a 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -11,7 +11,7 @@ env: jobs: build: name: Build and publish documentation - runs-on: macos-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -20,9 +20,17 @@ jobs: path: "**/cpm_modules" key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} + - name: Before Install + run: | + sudo apt-get install g++-10 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 90 + + - name: Install dependencies + run: sudo apt-get install libboost-dev + - name: Install dependencies run: | - brew install doxygen boost + sudo apt-get install doxygen pip3 install jinja2 Pygments - name: Build diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.old similarity index 100% rename from .github/workflows/macos.yml rename to .github/workflows/macos.old diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 59e9e56..e2343c2 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -15,7 +15,7 @@ env: jobs: build: - runs-on: macos-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -25,10 +25,17 @@ jobs: path: "**/cpm_modules" key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} + - name: Before Install + run: | + sudo apt-get install g++-10 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 90 + + - name: Install dependencies + run: sudo apt-get install libboost-dev + - name: Install format dependencies run: | - brew install boost - brew install clang-format + sudo apt-get install clang-format pip3 install cmake_format==0.6.11 pyyaml - name: configure diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e278c48..ab8eb03 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -39,7 +39,7 @@ jobs: conda list conda config --show-sources conda config --show - conda install -c conda-forge cmake boost + conda install -c conda-forge cmake boost=1.74 - name: configure run: cmake -Stest -Bbuild diff --git a/include/projgeom/ck_plane.hpp b/include/projgeom/ck_plane.hpp index 1f8523e..7aed9f6 100644 --- a/include/projgeom/ck_plane.hpp +++ b/include/projgeom/ck_plane.hpp @@ -1,317 +1,269 @@ #pragma once +#include // std::is_base_of_v + #include "pg_common.hpp" #include "proj_plane.hpp" #include "proj_plane_concepts.h" #include "proj_plane_measure.hpp" -#include // std::is_base_of_v - -namespace fun -{ - -/*! - * @brief - * - * @tparam _P - * @tparam _L - * @tparam Derived - */ -template class Derived> -requires Projective_plane_prim<_P, _L> // c++20 concept -struct ck -{ - using point_t = _P; - using line_t = _L; - using cDer = const Derived<_P, _L>; - cDer& self = *static_cast(this); - - /** - * @brief construct ck object - * - */ - constexpr ck() noexcept - { - static_assert(std::is_base_of_v, Derived<_P, _L>>); - } +namespace fun { /*! - * @brief is perpendicular + * @brief * - * @tparam L - * @param[in] l - * @param[in] m - * @return true - * @return false + * @tparam _P + * @tparam _L + * @tparam Derived */ - constexpr auto is_perpendicular(const _L& l, const _L& m) const -> bool - { - return incident(m, self.perp(l)); - } + template class Derived> + requires Projective_plane_prim<_P, _L> // c++20 concept + struct ck { + using point_t = _P; + using line_t = _L; - /*! - * @brief altitude - * - * @param[in] p - * @param[in] l - * @return L - */ - template - requires Projective_plane_prim // c++20 concept - constexpr auto altitude(const P& p, const L& l) const -> L - { - return p * self.perp(l); - } + using cDer = const Derived<_P, _L>; + cDer& self = *static_cast(this); - /*! - * @brief altitudes of triangle - * - * @param[in] tri - * @return std::tuple - */ - template - constexpr auto tri_altitude(const Triple

& tri) const - { - const auto [l1, l2, l3] = tri_dual(tri); - const auto& [a1, a2, a3] = tri; + /** + * @brief construct ck object + * + */ + constexpr ck() noexcept { + static_assert(std::is_base_of_v, Derived<_P, _L>>); + } - return std::tuple {this->altitude(a1, l1), this->altitude(a2, l2), - this->altitude(a3, l3)}; - } + /*! + * @brief is perpendicular + * + * @tparam L + * @param[in] l + * @param[in] m + * @return true + * @return false + */ + constexpr auto is_perpendicular(const _L& l, const _L& m) const -> bool { + return incident(m, self.perp(l)); + } - /*! - * @brief ortho-center - * - * @param[in] tri - * @return P - */ - template - constexpr auto orthocenter(const Triple

& tri) const -> P - { - const auto& [a1, a2, a3] = tri; + /*! + * @brief altitude + * + * @param[in] p + * @param[in] l + * @return L + */ + template + requires Projective_plane_prim // c++20 concept + constexpr auto altitude(const P& p, const L& l) const -> L { return p * self.perp(l); } - const auto t1 = this->altitude(a1, a2 * a3); - const auto t2 = this->altitude(a2, a1 * a3); - return t1 * t2; - } + /*! + * @brief altitudes of triangle + * + * @param[in] tri + * @return std::tuple + */ + template + constexpr auto tri_altitude(const Triple

& tri) const { + const auto [l1, l2, l3] = tri_dual(tri); + const auto& [a1, a2, a3] = tri; - /** - * @brief reflect - * - * @param[in] m - * @return auto - */ - template - auto reflect(const P& m) const - { - return involution {self.perp(m), P {m}}; - } + return std::tuple{this->altitude(a1, l1), this->altitude(a2, l2), + this->altitude(a3, l3)}; + } - /** - * @brief measure of triangle - * - * @param[in] tri - * @return constexpr auto - */ - template - constexpr auto tri_measure(const Triple

& tri) const - { - const auto& [a1, a2, a3] = tri; + /*! + * @brief ortho-center + * + * @param[in] tri + * @return P + */ + template constexpr auto orthocenter(const Triple

& tri) const + -> P { + const auto& [a1, a2, a3] = tri; - return std::tuple { - self.measure(a2, a3), self.measure(a1, a3), self.measure(a1, a2)}; - } + const auto t1 = this->altitude(a1, a2 * a3); + const auto t2 = this->altitude(a2, a1 * a3); + return t1 * t2; + } - /** - * @brief quadrance between two points - * - * @param[in] p - * @param[in] q - * @return constexpr auto - */ - constexpr auto quadrance(const _P& p, const _P& q) const - { - return self.measure(p, q); - } + /** + * @brief reflect + * + * @param[in] m + * @return auto + */ + template auto reflect(const P& m) const { + return involution{self.perp(m), P{m}}; + } - /** - * @brief spread between two lines - * - * @param[in] l - * @param[in] m - * @return constexpr auto - */ - constexpr auto spread(const _L& l, const _L& m) const - { - return self.measure(l, m); - } + /** + * @brief measure of triangle + * + * @param[in] tri + * @return constexpr auto + */ + template constexpr auto tri_measure(const Triple

& tri) const { + const auto& [a1, a2, a3] = tri; - /** - * @brief quadrances of triangle - * - * @param[in] triangle - * @return constexpr auto - */ - constexpr auto tri_quadrance(const Triple<_P>& triangle) const - { - return this->tri_measure(triangle); - } + return std::tuple{self.measure(a2, a3), self.measure(a1, a3), self.measure(a1, a2)}; + } - /** - * @brief spreads of triangle - * - * @param[in] trilateral - * @return constexpr auto - */ - constexpr auto tri_spread(const Triple<_L>& trilateral) const - { - return this->tri_measure(trilateral); - } -}; + /** + * @brief quadrance between two points + * + * @param[in] p + * @param[in] q + * @return constexpr auto + */ + constexpr auto quadrance(const _P& p, const _P& q) const { return self.measure(p, q); } -/*! - * @brief check sine law - * - * @tparam Q_t - * @tparam S_t - * @param[in] Q - * @param[in] S - * @return true - * @return false - */ -template -constexpr auto check_sine_law(const Triple& Q, const Triple& S) - -> bool -{ - const auto& [q1, q2, q3] = Q; - const auto& [s1, s2, s3] = S; - return (s1 * q2 == s2 * q1) && (s2 * q3 == s3 * q2); -} + /** + * @brief spread between two lines + * + * @param[in] l + * @param[in] m + * @return constexpr auto + */ + constexpr auto spread(const _L& l, const _L& m) const { return self.measure(l, m); } -/*! - * @brief Elliptic Plane - * - * @tparam P - * @tparam P::dual - */ -template -requires Projective_plane_prim // c++20 concept -struct ellck : ck -{ - /** - * @brief perp (polar) of point - * - * @param[in] v - * @return L - */ - constexpr auto perp(const P& v) const -> L - { - return L(v); - } + /** + * @brief quadrances of triangle + * + * @param[in] triangle + * @return constexpr auto + */ + constexpr auto tri_quadrance(const Triple<_P>& triangle) const { + return this->tri_measure(triangle); + } - /** - * @brief perp (pole) of line + /** + * @brief spreads of triangle + * + * @param[in] trilateral + * @return constexpr auto + */ + constexpr auto tri_spread(const Triple<_L>& trilateral) const { + return this->tri_measure(trilateral); + } + }; + + /*! + * @brief check sine law * - * @param[in] v - * @return P + * @tparam Q_t + * @tparam S_t + * @param[in] Q + * @param[in] S + * @return true + * @return false */ - constexpr auto perp(const L& v) const -> P - { - return P(v); + template + constexpr auto check_sine_law(const Triple& Q, const Triple& S) -> bool { + const auto& [q1, q2, q3] = Q; + const auto& [s1, s2, s3] = S; + return (s1 * q2 == s2 * q1) && (s2 * q3 == s3 * q2); } - /** - * @brief measure between two objects + /*! + * @brief Elliptic Plane * - * @tparam _P - * @param[in] a1 - * @param[in] a2 - * @return constexpr auto + * @tparam P + * @tparam P::dual */ - template - constexpr auto measure(const _P& a1, const _P& a2) const - { - return 1 - x_ratio(a1, a2, this->perp(a2), this->perp(a1)); - } -}; + template + requires Projective_plane_prim // c++20 concept + struct ellck : ck { + /** + * @brief perp (polar) of point + * + * @param[in] v + * @return L + */ + constexpr auto perp(const P& v) const -> L { return L(v); } -/*! - * @brief Hyperbolic Plane - * - * @tparam P - * @tparam P::dual - */ -template -requires Projective_plane_prim // c++20 concept -struct hyck : ck -{ - /** - * @brief perp (polar) of point + /** + * @brief perp (pole) of line + * + * @param[in] v + * @return P + */ + constexpr auto perp(const L& v) const -> P { return P(v); } + + /** + * @brief measure between two objects + * + * @tparam _P + * @param[in] a1 + * @param[in] a2 + * @return constexpr auto + */ + template constexpr auto measure(const _P& a1, const _P& a2) const { + return 1 - x_ratio(a1, a2, this->perp(a2), this->perp(a1)); + } + }; + + /*! + * @brief Hyperbolic Plane * - * @param[in] v - * @return L + * @tparam P + * @tparam P::dual */ - constexpr auto perp(const P& v) const -> L - { - return L(v[0], v[1], -v[2]); - } + template + requires Projective_plane_prim // c++20 concept + struct hyck : ck { + /** + * @brief perp (polar) of point + * + * @param[in] v + * @return L + */ + constexpr auto perp(const P& v) const -> L { return L(v[0], v[1], -v[2]); } + + /** + * @brief perp (pole) of line + * + * @param[in] v + * @return P + */ + constexpr auto perp(const L& v) const -> P { return P(v[0], v[1], -v[2]); } + + /** + * @brief measure between two objects + * + * @tparam _P + * @param[in] a1 + * @param[in] a2 + * @return constexpr auto + */ + template constexpr auto measure(const _P& a1, const _P& a2) const { + return 1 - x_ratio(a1, a2, this->perp(a2), this->perp(a1)); + } + }; - /** - * @brief perp (pole) of line + /*! + * @brief * - * @param[in] v - * @return P + * @tparam K + * @param[in] Q + * @return constexpr auto */ - constexpr auto perp(const L& v) const -> P - { - return P(v[0], v[1], -v[2]); + template constexpr auto check_cross_TQF(const Triple& Q) { + const auto& [q1, q2, q3] = Q; + return sq(q1 + q2 + q3) - 2 * (q1 * q1 + q2 * q2 + q3 * q3) - 4 * q1 * q2 * q3; } - /** - * @brief measure between two objects + /*! + * @brief * - * @tparam _P - * @param[in] a1 - * @param[in] a2 + * @tparam K + * @param[in] S + * @param[in] q3 * @return constexpr auto */ - template - constexpr auto measure(const _P& a1, const _P& a2) const - { - return 1 - x_ratio(a1, a2, this->perp(a2), this->perp(a1)); + template constexpr auto check_cross_law(const Triple& S, const K& q3) { + const auto& [s1, s2, s3] = S; + return sq(s1 * s2 * q3 - (s1 + s2 + s3) + 2) - 4 * (1 - s1) * (1 - s2) * (1 - s3); } -}; - -/*! - * @brief - * - * @tparam K - * @param[in] Q - * @return constexpr auto - */ -template -constexpr auto check_cross_TQF(const Triple& Q) -{ - const auto& [q1, q2, q3] = Q; - return sq(q1 + q2 + q3) - 2 * (q1 * q1 + q2 * q2 + q3 * q3) - - 4 * q1 * q2 * q3; -} - -/*! - * @brief - * - * @tparam K - * @param[in] S - * @param[in] q3 - * @return constexpr auto - */ -template -constexpr auto check_cross_law(const Triple& S, const K& q3) -{ - const auto& [s1, s2, s3] = S; - return sq(s1 * s2 * q3 - (s1 + s2 + s3) + 2) - - 4 * (1 - s1) * (1 - s2) * (1 - s3); -} -} // namespace fun +} // namespace fun diff --git a/include/projgeom/common_concepts.h b/include/projgeom/common_concepts.h index 49108a5..f229c94 100644 --- a/include/projgeom/common_concepts.h +++ b/include/projgeom/common_concepts.h @@ -1,61 +1,54 @@ #pragma once -#include #include #include #include +#include // #include // #include -namespace fun -{ - -template -using Value_type = typename T::value_type; - -template -using Element_type = typename std::decay()))>::type; - -/** - * @brief Sequence - * - * @tparam T - */ -template -concept Sequence = requires(T t, Element_type x) -{ - { t.size() } -> std::convertible_to; - { t.empty() } -> std::convertible_to; - { t.back() } -> std::same_as >; - { t.push_back(x) }; -}; - - -template -concept ring = std::equality_comparable && requires(K a, K b) -{ - { a + b } -> std::convertible_to; - { a - b } -> std::convertible_to; - { a * b } -> std::convertible_to; - { a += b } -> std::same_as; - { a -= b } -> std::same_as; - { a *= b } -> std::same_as; - { -a } -> std::convertible_to; - { K(a) } -> std::convertible_to; - { K(0) } -> std::convertible_to; -}; - -template -concept ordered_ring = ring && std::totally_ordered; - - -template -concept Integral = ordered_ring && requires(Z a, Z b) -{ - { a % b } -> std::convertible_to; - { a / b } -> std::convertible_to; - { a %= b } -> std::same_as; - { a /= b } -> std::same_as; -}; - -} // namespace fun +namespace fun { + + template using Value_type = typename T::value_type; + + template using Element_type = + typename std::decay()))>::type; + + /** + * @brief Sequence + * + * @tparam T + */ + template + concept Sequence = requires(T t, Element_type x) { + { t.size() } -> std::convertible_to; + { t.empty() } -> std::convertible_to; + { t.back() } -> std::same_as >; + {t.push_back(x)}; + }; + + template + concept ring = std::equality_comparable && requires(K a, K b) { + { a + b } -> std::convertible_to; + { a - b } -> std::convertible_to; + { a* b } -> std::convertible_to; + { a += b } -> std::same_as; + { a -= b } -> std::same_as; + { a *= b } -> std::same_as; + { -a } -> std::convertible_to; + { K(a) } -> std::convertible_to; + { K(0) } -> std::convertible_to; + }; + + template + concept ordered_ring = ring && std::totally_ordered; + + template + concept Integral = ordered_ring && requires(Z a, Z b) { + { a % b } -> std::convertible_to; + { a / b } -> std::convertible_to; + { a %= b } -> std::same_as; + { a /= b } -> std::same_as; + }; + +} // namespace fun diff --git a/include/projgeom/euclid_plane.hpp b/include/projgeom/euclid_plane.hpp index d93348f..c9a5cb8 100644 --- a/include/projgeom/euclid_plane.hpp +++ b/include/projgeom/euclid_plane.hpp @@ -1,197 +1,173 @@ #pragma once -#include "pg_common.hpp" // import cross2, dot1 -#include "proj_plane.hpp" // import pg_point, involution, tri_func, quad_func, plucker -#include "proj_plane_concepts.h" #include -namespace fun -{ - -/*! - * @brief - * - * @param[in] l - * @return auto - */ -template // // and requires p[i] -constexpr auto fB(const L& l) -> typename L::dual -{ - return {l[0], l[1], 0}; -} - -/*! - * @brief - * - * @param[in] l - * @param[in] m - * @return true - * @return false - */ -template -constexpr auto is_perpendicular(const L& l, const L& m) -> bool -{ - return dot1(l, m) == 0; -} - -/*! - * @brief - * - * @param[in] l - * @param[in] m - * @return true - * @return false - */ -template -constexpr auto is_parallel(const L& l, const L& m) -> bool -{ - return cross2(l, m) == 0; -} - -/*! - * @brief - * - * @param[in] a - * @param[in] l - * @return L - */ -template -requires Projective_plane_coord -constexpr auto altitude(const P& a, const L& l) -> L -{ - return a * fB(l); -} - -/*! - * @brief - * - * @param[in] tri - * @return auto - */ -template -constexpr auto tri_altitude(const Triple

& tri) -{ - const auto& [a1, a2, a3] = tri; - return std::tuple { - altitude(a1, a2 * a3), altitude(a2, a3 * a1), altitude(a3, a1 * a2)}; -} - -/*! - * @brief - * - * @param[in] tri - * @return P - */ -template -constexpr auto orthocenter(const Triple

& tri) -> P -{ - const auto& [a1, a2, a3] = tri; - const auto t1 = altitude(a1, a2 * a3); - const auto t2 = altitude(a2, a1 * a3); - return t1 * t2; -} - -/*! - * @brief - * - * @param[in] m - * @return auto - */ -template -constexpr auto reflect(const L& m) -{ - return involution {m, fB(m)}; -} - -/*! - * @brief - * - * @param[in] a - * @param[in] b - * @return P - */ -template -constexpr auto midpoint(const P& a, const P& b) -> P -{ - return plucker(b[2], a, a[2], b); -} - -/*! - * @brief - * - * @param[in] tri - * @return auto - */ -template -constexpr auto tri_midpoint(const Triple

& tri) -> Triple

-{ - const auto& [a1, a2, a3] = tri; - return {midpoint(a1, a2), midpoint(a2, a3), midpoint(a1, a3)}; -} - - -/*! - * @brief - * - * @param[in] lda1 - * @param[in] mu1 - * @return P - */ -template -constexpr auto uc_point(const Value_type

& lda1, const Value_type

& mu1) -{ - const auto lda2 = lda1 * lda1; - const auto mu2 = mu1 * mu1; - return P {lda2 - mu2, 2 * lda1 * mu1, lda2 + mu2}; -} - -/*! - * @brief Archimedes's function - * - * @tparam _Q - * @param[in] a - * @param[in] b - * @param[in] c - * @return auto - */ -template -constexpr auto Ar(const _Q& a, const _Q& b, const _Q& c) -{ - return 4 * a * b - sq(a + b - c); -} - -/*! - * @brief Cyclic quadrilateral quadrea theorem - * - * @tparam _Q - * @param[in] a - * @param[in] b - * @param[in] c - * @param[in] d - * @return auto - */ -template -constexpr auto cqq(const _Q& a, const _Q& b, const _Q& c, const _Q& d) -{ - const auto t1 = 4 * a * b; - const auto t2 = 4 * c * d; - auto m = (t1 + t2) - sq(a + b - c - d); - auto p = m * m - 4 * t1 * t2; - return std::tuple {std::move(m), std::move(p)}; -} - -/*! - * @brief - * - * @tparam _Q - * @param[in] quad - * @return auto - */ -template -constexpr auto Ptolemy(const T& quad) -> bool -{ - const auto& [Q12, Q23, Q34, Q14, Q13, Q24] = quad; - return Ar(Q12 * Q34, Q23 * Q14, Q13 * Q24) == 0; -} - -} // namespace fun +#include "pg_common.hpp" // import cross2, dot1 +#include "proj_plane.hpp" // import pg_point, involution, tri_func, quad_func, plucker +#include "proj_plane_concepts.h" + +namespace fun { + + /*! + * @brief + * + * @param[in] l + * @return auto + */ + template // // and requires p[i] + constexpr auto fB(const L& l) -> typename L::dual { + return {l[0], l[1], 0}; + } + + /*! + * @brief + * + * @param[in] l + * @param[in] m + * @return true + * @return false + */ + template constexpr auto is_perpendicular(const L& l, const L& m) + -> bool { + return dot1(l, m) == 0; + } + + /*! + * @brief + * + * @param[in] l + * @param[in] m + * @return true + * @return false + */ + template constexpr auto is_parallel(const L& l, const L& m) + -> bool { + return cross2(l, m) == 0; + } + + /*! + * @brief + * + * @param[in] a + * @param[in] l + * @return L + */ + template + requires Projective_plane_coord + constexpr auto altitude(const P& a, const L& l) -> L { return a * fB(l); } + + /*! + * @brief + * + * @param[in] tri + * @return auto + */ + template constexpr auto tri_altitude(const Triple

& tri) { + const auto& [a1, a2, a3] = tri; + return std::tuple{altitude(a1, a2 * a3), altitude(a2, a3 * a1), altitude(a3, a1 * a2)}; + } + + /*! + * @brief + * + * @param[in] tri + * @return P + */ + template constexpr auto orthocenter(const Triple

& tri) -> P { + const auto& [a1, a2, a3] = tri; + const auto t1 = altitude(a1, a2 * a3); + const auto t2 = altitude(a2, a1 * a3); + return t1 * t2; + } + + /*! + * @brief + * + * @param[in] m + * @return auto + */ + template constexpr auto reflect(const L& m) { + return involution{m, fB(m)}; + } + + /*! + * @brief + * + * @param[in] a + * @param[in] b + * @return P + */ + template constexpr auto midpoint(const P& a, const P& b) -> P { + return plucker(b[2], a, a[2], b); + } + + /*! + * @brief + * + * @param[in] tri + * @return auto + */ + template constexpr auto tri_midpoint(const Triple

& tri) + -> Triple

{ + const auto& [a1, a2, a3] = tri; + return {midpoint(a1, a2), midpoint(a2, a3), midpoint(a1, a3)}; + } + + /*! + * @brief + * + * @param[in] lda1 + * @param[in] mu1 + * @return P + */ + template + constexpr auto uc_point(const Value_type

& lda1, const Value_type

& mu1) { + const auto lda2 = lda1 * lda1; + const auto mu2 = mu1 * mu1; + return P{lda2 - mu2, 2 * lda1 * mu1, lda2 + mu2}; + } + + /*! + * @brief Archimedes's function + * + * @tparam _Q + * @param[in] a + * @param[in] b + * @param[in] c + * @return auto + */ + template constexpr auto Ar(const _Q& a, const _Q& b, const _Q& c) { + return 4 * a * b - sq(a + b - c); + } + + /*! + * @brief Cyclic quadrilateral quadrea theorem + * + * @tparam _Q + * @param[in] a + * @param[in] b + * @param[in] c + * @param[in] d + * @return auto + */ + template constexpr auto cqq(const _Q& a, const _Q& b, const _Q& c, const _Q& d) { + const auto t1 = 4 * a * b; + const auto t2 = 4 * c * d; + auto m = (t1 + t2) - sq(a + b - c - d); + auto p = m * m - 4 * t1 * t2; + return std::tuple{std::move(m), std::move(p)}; + } + + /*! + * @brief + * + * @tparam _Q + * @param[in] quad + * @return auto + */ + template constexpr auto Ptolemy(const T& quad) -> bool { + const auto& [Q12, Q23, Q34, Q14, Q13, Q24] = quad; + return Ar(Q12 * Q34, Q23 * Q14, Q13 * Q24) == 0; + } + +} // namespace fun diff --git a/include/projgeom/euclid_plane_measure.hpp b/include/projgeom/euclid_plane_measure.hpp index 5f1b0a4..423d1a8 100644 --- a/include/projgeom/euclid_plane_measure.hpp +++ b/include/projgeom/euclid_plane_measure.hpp @@ -3,169 +3,146 @@ #include "euclid_plane.hpp" #include "fractions.hpp" -namespace fun -{ - -/*! - * @brief - * - * @tparam K - * @param[in] x1 - * @param[in] z1 - * @param[in] x2 - * @param[in] z2 - * @return auto - */ -template -requires Integral -inline constexpr auto quad1(const K& x1, const K& z1, const K& x2, const K& z2) -{ - return sq(Fraction(x1, z1) - Fraction(x2, z2)); -} - -/*! - * @brief - * - * @tparam K - * @param[in] x1 - * @param[in] z1 - * @param[in] x2 - * @param[in] z2 - * @return auto - */ -template -// requires (!Integral) -inline constexpr auto quad1(const K& x1, const K& z1, const K& x2, const K& z2) -{ - return sq(x1 / z1 - x2 / z2); -} - -/*! - * @brief - * - * @param[in] a1 - * @param[in] a2 - * @return auto - */ -template -inline constexpr auto quadrance(const P& a1, const P& a2) -{ - return quad1(a1[0], a1[2], a2[0], a2[2]) + - quad1(a1[1], a1[2], a2[1], a2[2]); -} - -template -inline constexpr auto quadrance_copy(const Args&... args) -{ - return std::make_tuple(quadrance(args.first, args.second)...); -} - -// Projective_plane2 { L } -// constexpr auto sbase(const L &l1, const L &l2, const Integer &d) { -// return Fraction(d, omgB(l1, l1)) * Fraction(d, omgB(l2, l2)); -// } - -/*! - * @brief - * - * @param[in] l1 - * @param[in] l2 - * @param[in] d - * @return auto - */ -template -inline constexpr auto sbase(const L& l1, const L& l2, const T& d) -{ - using K = Value_type; - if constexpr (Integral) - { - return Fraction(d, dot1(l1, l1)) * Fraction(d, dot1(l2, l2)); +namespace fun { + + /*! + * @brief + * + * @tparam K + * @param[in] x1 + * @param[in] z1 + * @param[in] x2 + * @param[in] z2 + * @return auto + */ + template + requires Integral + inline constexpr auto quad1(const K& x1, const K& z1, const K& x2, const K& z2) { + return sq(Fraction(x1, z1) - Fraction(x2, z2)); } - else - { - return (d * d) / (dot1(l1, l1) * dot1(l2, l2)); + + /*! + * @brief + * + * @tparam K + * @param[in] x1 + * @param[in] z1 + * @param[in] x2 + * @param[in] z2 + * @return auto + */ + template + // requires (!Integral) + inline constexpr auto quad1(const K& x1, const K& z1, const K& x2, const K& z2) { + return sq(x1 / z1 - x2 / z2); + } + + /*! + * @brief + * + * @param[in] a1 + * @param[in] a2 + * @return auto + */ + template inline constexpr auto quadrance(const P& a1, const P& a2) { + return quad1(a1[0], a1[2], a2[0], a2[2]) + quad1(a1[1], a1[2], a2[1], a2[2]); + } + + template inline constexpr auto quadrance_copy(const Args&... args) { + return std::make_tuple(quadrance(args.first, args.second)...); + } + + // Projective_plane2 { L } + // constexpr auto sbase(const L &l1, const L &l2, const Integer &d) { + // return Fraction(d, omgB(l1, l1)) * Fraction(d, omgB(l2, l2)); + // } + + /*! + * @brief + * + * @param[in] l1 + * @param[in] l2 + * @param[in] d + * @return auto + */ + template + inline constexpr auto sbase(const L& l1, const L& l2, const T& d) { + using K = Value_type; + if constexpr (Integral) { + return Fraction(d, dot1(l1, l1)) * Fraction(d, dot1(l2, l2)); + } else { + return (d * d) / (dot1(l1, l1) * dot1(l2, l2)); + } + } + + /*! + * @brief + * + * @param[in] l1 + * @param[in] l2 + * @return auto + */ + template inline constexpr auto spread(const L& l1, const L& l2) { + return sbase(l1, l2, cross2(l1, l2)); + } + + /*! + * @brief + * + * @param[in] triangle + * @return auto + */ + template + inline constexpr auto tri_quadrance(const Triple

& triangle) { + const auto& [a1, a2, a3] = triangle; + return std::tuple{quadrance(a2, a3), quadrance(a1, a3), quadrance(a1, a2)}; + } + + /*! + * @brief + * + * @param[in] trilateral + * @return auto + */ + template + inline constexpr auto tri_spread(const Triple& trilateral) { + const auto& [a1, a2, a3] = trilateral; + return std::tuple{spread(a2, a3), spread(a1, a3), spread(a1, a2)}; + } + + /*! + * @brief + * + * @param[in] l1 + * @param[in] l2 + * @return auto + */ + template inline constexpr auto cross_s(const L& l1, const L& l2) { + return sbase(l1, l2, dot1(l1, l2)); } -} - - -/*! - * @brief - * - * @param[in] l1 - * @param[in] l2 - * @return auto - */ -template -inline constexpr auto spread(const L& l1, const L& l2) -{ - return sbase(l1, l2, cross2(l1, l2)); -} - -/*! - * @brief - * - * @param[in] triangle - * @return auto - */ -template -inline constexpr auto tri_quadrance(const Triple

& triangle) -{ - const auto& [a1, a2, a3] = triangle; - return std::tuple {quadrance(a2, a3), quadrance(a1, a3), quadrance(a1, a2)}; -} - -/*! - * @brief - * - * @param[in] trilateral - * @return auto - */ -template -inline constexpr auto tri_spread(const Triple& trilateral) -{ - const auto& [a1, a2, a3] = trilateral; - return std::tuple {spread(a2, a3), spread(a1, a3), spread(a1, a2)}; -} - -/*! - * @brief - * - * @param[in] l1 - * @param[in] l2 - * @return auto - */ -template -inline constexpr auto cross_s(const L& l1, const L& l2) -{ - return sbase(l1, l2, dot1(l1, l2)); -} #include -/*! - * @brief - * - * @param[in] a - * @param[in] b - * @return auto - */ -template -inline constexpr auto distance(const P& a, const P& b) -{ - return std::sqrt(double(quadrance(a, b))); -} - -/*! - * @brief - * - * @param[in] l - * @param[in] m - * @return auto - */ -template -inline constexpr auto angle(const L& l, const L& m) -{ - return std::asin(std::sqrt(double(spread(l, m)))); -} - -} // namespace fun + /*! + * @brief + * + * @param[in] a + * @param[in] b + * @return auto + */ + template inline constexpr auto distance(const P& a, const P& b) { + return std::sqrt(double(quadrance(a, b))); + } + + /*! + * @brief + * + * @param[in] l + * @param[in] m + * @return auto + */ + template inline constexpr auto angle(const L& l, const L& m) { + return std::asin(std::sqrt(double(spread(l, m)))); + } + +} // namespace fun diff --git a/include/projgeom/fractions.hpp b/include/projgeom/fractions.hpp index 12bc014..7195bfe 100644 --- a/include/projgeom/fractions.hpp +++ b/include/projgeom/fractions.hpp @@ -7,615 +7,525 @@ #include // #include -#include "common_concepts.h" #include #include #include -namespace fun -{ - -/** - * @brief absolute (for unsigned) - * - * @tparam T - * @param a - * @return T - */ -template -requires std::is_unsigned_v -inline constexpr auto abs(const T& a) -> T -{ - return a; -} - -/** - * @brief absolute - * - * @tparam T - */ -template -requires (!std::is_unsigned_v && ordered_ring) -inline constexpr auto abs(const T& a) -> T -{ - return (a < T(0)) ? -a : a; -} - - -/*! - * @brief Greatest common divider - * - * @tparam _Mn - * @param[in] __m - * @param[in] __n - * @return _Mn - */ -template -inline constexpr auto gcd_recur(_Mn __m, _Mn __n) -> _Mn -{ - if (__n == 0) - { - return abs(__m); - } - return gcd_recur(__n, __m % __n); -} - -/*! - * @brief Greatest common divider - * - * @tparam _Mn - * @param[in] __m - * @param[in] __n - * @return _Mn - */ -template -inline constexpr auto gcd(_Mn __m, _Mn __n) -> _Mn -{ - if (__m == 0) - { - return abs(__n); - } - return gcd_recur(__m, __n); -} - -/*! - * @brief Least common multiple - * - * @tparam _Mn - * @param[in] __m - * @param[in] __n - * @return _Mn - */ -template -inline constexpr auto lcm(_Mn __m, _Mn __n) -> _Mn -{ - if (__m == 0 || __n == 0) - { - return 0; - } - return (abs(__m) / gcd(__m, __n)) * abs(__n); -} - - -template -struct Fraction : boost::totally_ordered, - boost::totally_ordered2, Z, - boost::multipliable2, Z, - boost::dividable2, Z>>>> -{ - Z _num; - Z _den; +#include "common_concepts.h" +namespace fun { - /*! - * @brief Construct a new Fraction object + /** + * @brief absolute (for unsigned) * - * @param[in] num - * @param[in] den + * @tparam T + * @param a + * @return T */ - constexpr Fraction(Z num, Z den) - : _num {std::move(num)} - , _den {std::move(den)} - { - this->normalize(); - } + template + requires std::is_unsigned_v + inline constexpr auto abs(const T& a) -> T { return a; } - constexpr void normalize() - { - Z common = gcd(this->_num, this->_den); - if (common == Z(1) || common == Z(0)) - { - return; - } - if (this->_den < Z(0)) - { - common = -common; - } - this->_num /= common; - this->_den /= common; - } - - /*! - * @brief Construct a new Fraction object + /** + * @brief absolute * - * @param[in] num + * @tparam T */ - constexpr explicit Fraction(Z&& num) - : _num {std::move(num)} - , _den(Z(1)) - { + template + requires(!std::is_unsigned_v && ordered_ring) inline constexpr auto abs(const T& a) -> T { + return (a < T(0)) ? -a : a; } /*! - * @brief Construct a new Fraction object + * @brief Greatest common divider * - * @param[in] num + * @tparam _Mn + * @param[in] __m + * @param[in] __n + * @return _Mn */ - constexpr explicit Fraction(const Z& num) - : _num {num} - , _den(1) - { + template inline constexpr auto gcd_recur(_Mn __m, _Mn __n) -> _Mn { + if (__n == 0) { + return abs(__m); + } + return gcd_recur(__n, __m % __n); } /*! - * @brief Construct a new Fraction object + * @brief Greatest common divider * - * @param[in] num + * @tparam _Mn + * @param[in] __m + * @param[in] __n + * @return _Mn */ - constexpr Fraction() - : _num(0) - , _den(1) - { + template inline constexpr auto gcd(_Mn __m, _Mn __n) -> _Mn { + if (__m == 0) { + return abs(__n); + } + return gcd_recur(__m, __n); } /*! - * @brief + * @brief Least common multiple * - * @return const Z& + * @tparam _Mn + * @param[in] __m + * @param[in] __n + * @return _Mn */ - [[nodiscard]] constexpr auto num() const noexcept -> const Z& - { - return _num; - } + template inline constexpr auto lcm(_Mn __m, _Mn __n) -> _Mn { + if (__m == 0 || __n == 0) { + return 0; + } + return (abs(__m) / gcd(__m, __n)) * abs(__n); + } + + template struct Fraction + : boost::totally_ordered< + Fraction, + boost::totally_ordered2< + Fraction, Z, + boost::multipliable2, Z, boost::dividable2, Z>>>> { + Z _num; + Z _den; + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + * @param[in] den + */ + constexpr Fraction(Z num, Z den) : _num{std::move(num)}, _den{std::move(den)} { + this->normalize(); + } - /*! - * @brief - * - * @return const Z& - */ - [[nodiscard]] constexpr auto den() const noexcept -> const Z& - { - return _den; - } + constexpr void normalize() { + Z common = gcd(this->_num, this->_den); + if (common == Z(1) || common == Z(0)) { + return; + } + if (this->_den < Z(0)) { + common = -common; + } + this->_num /= common; + this->_den /= common; + } - /*! - * @brief - * - * @return Fraction - */ - [[nodiscard]] constexpr auto abs() const -> Fraction - { - return Fraction(abs(this->_num), abs(this->_den)); - } + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr explicit Fraction(Z&& num) : _num{std::move(num)}, _den(Z(1)) {} + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr explicit Fraction(const Z& num) : _num{num}, _den(1) {} + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr Fraction() : _num(0), _den(1) {} + + /*! + * @brief + * + * @return const Z& + */ + [[nodiscard]] constexpr auto num() const noexcept -> const Z& { return _num; } + + /*! + * @brief + * + * @return const Z& + */ + [[nodiscard]] constexpr auto den() const noexcept -> const Z& { return _den; } + + /*! + * @brief + * + * @return Fraction + */ + [[nodiscard]] constexpr auto abs() const -> Fraction { + return Fraction(abs(this->_num), abs(this->_den)); + } - /*! - * @brief - * - */ - constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v) - { - std::swap(this->_num, this->_den); - } + /*! + * @brief + * + */ + constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v) { + std::swap(this->_num, this->_den); + } - /*! - * @brief - * - * @return Fraction - */ - constexpr auto operator-() const -> Fraction - { - auto res = Fraction(*this); - res._num = -res._num; - return res; - } + /*! + * @brief + * + * @return Fraction + */ + constexpr auto operator-() const -> Fraction { + auto res = Fraction(*this); + res._num = -res._num; + return res; + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator+(const Fraction& frac) const -> Fraction - { - if (this->_den == frac._den) - { - return Fraction(this->_num + frac._num, this->_den); + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator+(const Fraction& frac) const -> Fraction { + if (this->_den == frac._den) { + return Fraction(this->_num + frac._num, this->_den); + } + auto d = this->_den * frac._den; + auto n = frac._den * this->_num + this->_den * frac._num; + return Fraction(n, d); } - auto d = this->_den * frac._den; - auto n = frac._den * this->_num + this->_den * frac._num; - return Fraction(n, d); - } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator-(const Fraction& frac) const -> Fraction - { - return *this + (-frac); - } + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator-(const Fraction& frac) const -> Fraction { return *this + (-frac); } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator*(const Fraction& frac) const -> Fraction { + auto n = this->_num * frac._num; + auto d = this->_den * frac._den; + return Fraction(std::move(n), std::move(d)); + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator*(const Fraction& frac) const -> Fraction - { - auto n = this->_num * frac._num; - auto d = this->_den * frac._den; - return Fraction(std::move(n), std::move(d)); - } + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator/(Fraction frac) const -> Fraction { + frac.reciprocal(); + return *this * frac; + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator/(Fraction frac) const -> Fraction - { - frac.reciprocal(); - return *this * frac; - } + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator+(const Z& i) const -> Fraction { + auto n = this->_num + this->_den * i; + return Fraction(std::move(n), this->_den); + } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator-(const Z& i) const -> Fraction { return *this + (-i); } + + // /*! + // * @brief + // * + // * @param[in] i + // * @return Fraction + // */ + // constexpr Fraction operator*(const Z& i) const noexcept + // { + // auto n = _num * i; + // return Fraction(n, _den); + // } + + // /*! + // * @brief + // * + // * @param[in] i + // * @return Fraction + // */ + // constexpr Fraction operator/(const Z& i) const noexcept + // { + // auto d = _den * i; + // return Fraction(_num, d); + // } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator+=(const Fraction& frac) -> Fraction& { + return *this = *this + frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator-=(const Fraction& frac) -> Fraction& { + return *this = *this - frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator*=(const Fraction& frac) -> Fraction& { + return *this = *this * frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator/=(const Fraction& frac) -> Fraction& { + return *this = *this / frac; + } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator+=(const Z& i) -> Fraction& { return *this = *this + i; } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator-=(const Z& i) -> Fraction& { return *this = *this - i; } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator*=(const Z& i) -> Fraction& { + const auto common = gcd(i, this->_den); + if (common == Z(1)) { + this->_num *= i; + } + // else if (common == Z(0)) [[unlikely]] // both i and den are zero + // { + // this->_num = Z(0); + // } + else { + this->_num *= (i / common); + this->_den /= common; + } + return *this; + } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator/=(const Z& i) -> Fraction& { + const auto common = gcd(this->_num, i); + if (common == Z(1)) { + this->_den *= i; + } + // else if (common == Z(0)) [[unlikely]] // both i and num are zero + // { + // this->_den = Z(0); + // } + else { + this->_den *= (i / common); + this->_num /= common; + } + return *this; + } + + /*! + * @brief Three way comparison + * + * @param[in] frac + * @return auto + */ + template constexpr auto cmp(const Fraction& frac) const -> Fraction& { + if (this->_den == frac._den) { + return (this->_num - frac._num) * this->_den; + } + return this->_num * frac._den - this->_den * frac._num; + } + + template constexpr auto operator==(const Fraction& rhs) const -> bool { + if (this->_den == rhs._den) { + return this->_num == rhs._num; + } + + return this->_num * rhs._den == this->_den * rhs._num; + } + + template constexpr auto operator<(const Fraction& rhs) const -> bool { + if (this->_den == rhs._den) { + return this->_num < rhs._num; + } + + return this->_num * rhs._den < this->_den * rhs._num; + } + + /** + * @brief + * + */ + constexpr auto operator==(const Z& rhs) const -> bool { + return this->_den == Z(1) && this->_num == rhs; + } + + /** + * @brief + * + */ + constexpr auto operator<(const Z& rhs) const -> bool { + return this->_num < this->_den * rhs; + } + + /** + * @brief + * + */ + constexpr auto operator>(const Z& rhs) const -> bool { + return this->_num > this->_den * rhs; + } + + // /*! + // * @brief + // * + // * @return double + // */ + // constexpr explicit operator double()) + // { + // return double(_num) / _den; + // } + + // /** + // * @brief + // * + // */ + // friend constexpr bool operator<(const Z& lhs, const Fraction& rhs)) + // { + // return lhs * rhs.den() < rhs.num(); + // } + }; /*! * @brief * - * @param[in] i - * @return Fraction + * @param[in] c + * @param[in] frac + * @return Fraction */ - constexpr auto operator+(const Z& i) const -> Fraction - { - auto n = this->_num + this->_den * i; - return Fraction(std::move(n), this->_den); + template constexpr auto operator+(const Z& c, const Fraction& frac) + -> Fraction { + return frac + c; } /*! * @brief * - * @param[in] i - * @return Fraction + * @param[in] c + * @param[in] frac + * @return Fraction */ - constexpr auto operator-(const Z& i) const -> Fraction - { - return *this + (-i); + template constexpr auto operator-(const Z& c, const Fraction& frac) + -> Fraction { + return c + (-frac); } // /*! // * @brief // * - // * @param[in] i - // * @return Fraction + // * @param[in] c + // * @param[in] frac + // * @return Fraction // */ - // constexpr Fraction operator*(const Z& i) const noexcept + // template + // constexpr Fraction operator*(const Z& c, const Fraction& frac) // { - // auto n = _num * i; - // return Fraction(n, _den); + // return frac * c; // } - // /*! - // * @brief - // * - // * @param[in] i - // * @return Fraction - // */ - // constexpr Fraction operator/(const Z& i) const noexcept - // { - // auto d = _den * i; - // return Fraction(_num, d); - // } - - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator+=(const Fraction& frac) -> Fraction& - { - return *this = *this + frac; - } - /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator-=(const Fraction& frac) -> Fraction& - { - return *this = *this - frac; + template constexpr auto operator+(int&& c, const Fraction& frac) + -> Fraction { + return frac + c; } /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator*=(const Fraction& frac) -> Fraction& - { - return *this = *this * frac; + template constexpr auto operator-(int&& c, const Fraction& frac) + -> Fraction { + return (-frac) + c; } /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator/=(const Fraction& frac) -> Fraction& - { - return *this = *this / frac; + template constexpr auto operator*(int&& c, const Fraction& frac) + -> Fraction { + return frac * c; } /*! * @brief * - * @param[in] i - * @return Fraction - */ - constexpr auto operator+=(const Z& i) -> Fraction& - { - return *this = *this + i; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator-=(const Z& i) -> Fraction& - { - return *this = *this - i; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator*=(const Z& i) -> Fraction& - { - const auto common = gcd(i, this->_den); - if (common == Z(1)) - { - this->_num *= i; - } - // else if (common == Z(0)) [[unlikely]] // both i and den are zero - // { - // this->_num = Z(0); - // } - else - { - this->_num *= (i / common); - this->_den /= common; - } - return *this; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator/=(const Z& i) -> Fraction& - { - const auto common = gcd(this->_num, i); - if (common == Z(1)) - { - this->_den *= i; - } - // else if (common == Z(0)) [[unlikely]] // both i and num are zero - // { - // this->_den = Z(0); - // } - else - { - this->_den *= (i / common); - this->_num /= common; - } - return *this; - } - - /*! - * @brief Three way comparison - * + * @tparam _Stream + * @tparam Z + * @param[in] os * @param[in] frac - * @return auto - */ - template - constexpr auto cmp(const Fraction& frac) const -> Fraction& - { - if (this->_den == frac._den) - { - return (this->_num - frac._num) * this->_den; - } - return this->_num * frac._den - this->_den * frac._num; - } - - template - constexpr auto operator==(const Fraction& rhs) const -> bool - { - if (this->_den == rhs._den) - { - return this->_num == rhs._num; - } - - return this->_num * rhs._den == this->_den * rhs._num; - } - - template - constexpr auto operator<(const Fraction& rhs) const -> bool - { - if (this->_den == rhs._den) - { - return this->_num < rhs._num; - } - - return this->_num * rhs._den < this->_den * rhs._num; - } - - /** - * @brief - * - */ - constexpr auto operator==(const Z& rhs) const -> bool - { - return this->_den == Z(1) && this->_num == rhs; - } - - /** - * @brief - * + * @return _Stream& */ - constexpr auto operator<(const Z& rhs) const -> bool - { - return this->_num < this->_den * rhs; + template auto operator<<(_Stream& os, const Fraction& frac) + -> _Stream& { + os << frac.num() << "/" << frac.den(); + return os; } - /** - * @brief - * - */ - constexpr auto operator>(const Z& rhs) const -> bool - { - return this->_num > this->_den * rhs; - } - - // /*! - // * @brief - // * - // * @return double - // */ - // constexpr explicit operator double()) - // { - // return double(_num) / _den; - // } - - // /** - // * @brief - // * - // */ - // friend constexpr bool operator<(const Z& lhs, const Fraction& rhs)) - // { - // return lhs * rhs.den() < rhs.num(); - // } -}; - - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator+(const Z& c, const Fraction& frac) -> Fraction -{ - return frac + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator-(const Z& c, const Fraction& frac) -> Fraction -{ - return c + (-frac); -} - -// /*! -// * @brief -// * -// * @param[in] c -// * @param[in] frac -// * @return Fraction -// */ -// template -// constexpr Fraction operator*(const Z& c, const Fraction& frac) -// { -// return frac * c; -// } - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator+(int&& c, const Fraction& frac) -> Fraction -{ - return frac + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator-(int&& c, const Fraction& frac) -> Fraction -{ - return (-frac) + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator*(int&& c, const Fraction& frac) -> Fraction -{ - return frac * c; -} - -/*! - * @brief - * - * @tparam _Stream - * @tparam Z - * @param[in] os - * @param[in] frac - * @return _Stream& - */ -template -auto operator<<(_Stream& os, const Fraction& frac) -> _Stream& -{ - os << frac.num() << "/" << frac.den(); - return os; -} - -// For template deduction -// Integral{Z} Fraction(const Z &, const Z &) noexcept -> Fraction; + // For template deduction + // Integral{Z} Fraction(const Z &, const Z &) noexcept -> Fraction; -} // namespace fun +} // namespace fun diff --git a/include/projgeom/fractions_gcd.hpp b/include/projgeom/fractions_gcd.hpp index c3b459c..15a0a0a 100644 --- a/include/projgeom/fractions_gcd.hpp +++ b/include/projgeom/fractions_gcd.hpp @@ -9,590 +9,502 @@ // #include #include #include + #include "common_concepts.h" -namespace fun -{ - -template -requires std::is_unsigned_v -constexpr auto abs(const T& a) -> T -{ - return a; -} - -template -requires (!std::is_unsigned_v && ordered_ring) -constexpr auto abs(const T& a) -> T -{ - return (a < T(0))? -a : a; -} - -template -requires Integral -constexpr auto gcd_recur(const T& a, const T& b) -> T -{ - // if (a == T(0)) return abs(b); - if (b == T(0)) return abs(a); - return gcd_recur(b, a % b); -} - -template -requires Integral -constexpr auto gcd(const T& a, const T& b) -> T -{ - if (a == T(0)) return abs(b); - // if (b == T(0)) return abs(a); - return gcd_recur(a, b); -} - -/*! - * @brief Least common multiple - * - * @tparam _Mn - * @param[in] __m - * @param[in] __n - * @return _Mn - */ -template -inline constexpr auto lcm(_Mn __m, _Mn __n) -> _Mn -{ - if (__m == 0 || __n == 0) return 0; - return (abs(__m) / gcd(__m, __n)) * abs(__n); -} - - -template -struct Fraction : boost::totally_ordered, - boost::totally_ordered2, Z, - boost::multipliable2, Z, - boost::dividable2, Z>>>> -{ - Z _num; - Z _den; +namespace fun { - /*! - * @brief Construct a new Fraction object - * - * @param[in] num - * @param[in] den - */ - constexpr Fraction(Z&& num, Z&& den) - : _num {std::move(num)} - , _den {std::move(den)} - { - this->normalize(); - } + template + requires std::is_unsigned_v + constexpr auto abs(const T& a) -> T { return a; } - /*! - * @brief Construct a new Fraction object - * - * @param[in] num - * @param[in] den - */ - constexpr Fraction(const Z& num, const Z& den) - : _num {num} - , _den {den} - { - this->normalize(); + template + requires(!std::is_unsigned_v && ordered_ring) constexpr auto abs(const T& a) -> T { + return (a < T(0)) ? -a : a; } - constexpr void normalize() - { - Z common = gcd(this->_num, this->_den); - if (common == Z(1) || common == Z(0)) - { - return; - } - if (this->_den < Z(0)) - { - common = -common; - } - this->_num /= common; - this->_den /= common; + template + requires Integral + constexpr auto gcd_recur(const T& a, const T& b) -> T { + // if (a == T(0)) return abs(b); + if (b == T(0)) return abs(a); + return gcd_recur(b, a % b); } - /*! - * @brief Construct a new Fraction object - * - * @param[in] num - */ - constexpr explicit Fraction(Z&& num) - : _num {std::move(num)} - , _den(Z(1)) - { + template + requires Integral + constexpr auto gcd(const T& a, const T& b) -> T { + if (a == T(0)) return abs(b); + // if (b == T(0)) return abs(a); + return gcd_recur(a, b); } /*! - * @brief Construct a new Fraction object + * @brief Least common multiple * - * @param[in] num + * @tparam _Mn + * @param[in] __m + * @param[in] __n + * @return _Mn */ - constexpr explicit Fraction(const Z& num) - : _num {num} - , _den(1) - { + template inline constexpr auto lcm(_Mn __m, _Mn __n) -> _Mn { + if (__m == 0 || __n == 0) return 0; + return (abs(__m) / gcd(__m, __n)) * abs(__n); } - /*! - * @brief Construct a new Fraction object - * - * @param[in] num - */ - constexpr Fraction() - : _num (0) - , _den (1) - { - } + template struct Fraction + : boost::totally_ordered< + Fraction, + boost::totally_ordered2< + Fraction, Z, + boost::multipliable2, Z, boost::dividable2, Z>>>> { + Z _num; + Z _den; + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + * @param[in] den + */ + constexpr Fraction(Z&& num, Z&& den) : _num{std::move(num)}, _den{std::move(den)} { + this->normalize(); + } - /*! - * @brief - * - * @return const Z& - */ - constexpr auto num() const noexcept -> const Z& - { - return _num; - } + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + * @param[in] den + */ + constexpr Fraction(const Z& num, const Z& den) : _num{num}, _den{den} { this->normalize(); } + + constexpr void normalize() { + Z common = gcd(this->_num, this->_den); + if (common == Z(1) || common == Z(0)) { + return; + } + if (this->_den < Z(0)) { + common = -common; + } + this->_num /= common; + this->_den /= common; + } - /*! - * @brief - * - * @return const Z& - */ - constexpr auto den() const noexcept -> const Z& - { - return _den; - } + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr explicit Fraction(Z&& num) : _num{std::move(num)}, _den(Z(1)) {} + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr explicit Fraction(const Z& num) : _num{num}, _den(1) {} + + /*! + * @brief Construct a new Fraction object + * + * @param[in] num + */ + constexpr Fraction() : _num(0), _den(1) {} + + /*! + * @brief + * + * @return const Z& + */ + constexpr auto num() const noexcept -> const Z& { return _num; } + + /*! + * @brief + * + * @return const Z& + */ + constexpr auto den() const noexcept -> const Z& { return _den; } + + /*! + * @brief + * + * @return Fraction + */ + constexpr auto abs() const -> Fraction { + return Fraction(abs(this->_num), abs(this->_den)); + } - /*! - * @brief - * - * @return Fraction - */ - constexpr auto abs() const -> Fraction - { - return Fraction(abs(this->_num), abs(this->_den)); - } + /*! + * @brief + * + */ + constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v) { + std::swap(this->_num, this->_den); + } - /*! - * @brief - * - */ - constexpr void reciprocal() noexcept(std::is_nothrow_swappable_v) - { - std::swap(this->_num, this->_den); - } + /*! + * @brief + * + * @return Fraction + */ + constexpr auto operator-() const -> Fraction { + auto res = Fraction(*this); + res._num = -res._num; + return res; + } - /*! - * @brief - * - * @return Fraction - */ - constexpr auto operator-() const -> Fraction - { - auto res = Fraction(*this); - res._num = -res._num; - return res; - } + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator+(const Fraction& frac) const -> Fraction { + if (this->_den == frac._den) { + return Fraction(this->_num + frac._num, this->_den); + } + auto d = this->_den * frac._den; + auto n = frac._den * this->_num + this->_den * frac._num; + return Fraction(n, d); + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator+(const Fraction& frac) const -> Fraction - { - if (this->_den == frac._den) - { - return Fraction(this->_num + frac._num, this->_den); + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator-(const Fraction& frac) const -> Fraction { return *this + (-frac); } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator*(const Fraction& frac) const -> Fraction { + auto n = this->_num * frac._num; + auto d = this->_den * frac._den; + return Fraction(std::move(n), std::move(d)); } - auto d = this->_den * frac._den; - auto n = frac._den * this->_num + this->_den * frac._num; - return Fraction(n, d); - } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator-(const Fraction& frac) const -> Fraction - { - return *this + (-frac); - } + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator/(Fraction frac) const -> Fraction { + frac.reciprocal(); + return *this * frac; + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator*(const Fraction& frac) const -> Fraction - { - auto n = this->_num * frac._num; - auto d = this->_den * frac._den; - return Fraction(std::move(n), std::move(d)); - } + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator+(const Z& i) const -> Fraction { + auto n = this->_num + this->_den * i; + return Fraction(std::move(n), this->_den); + } - /*! - * @brief - * - * @param[in] frac - * @return Fraction - */ - constexpr auto operator/(Fraction frac) const -> Fraction - { - frac.reciprocal(); - return *this * frac; - } + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator-(const Z& i) const -> Fraction { return *this + (-i); } + + // /*! + // * @brief + // * + // * @param[in] i + // * @return Fraction + // */ + // constexpr Fraction operator*(const Z& i) const noexcept + // { + // auto n = _num * i; + // return Fraction(n, _den); + // } + + // /*! + // * @brief + // * + // * @param[in] i + // * @return Fraction + // */ + // constexpr Fraction operator/(const Z& i) const noexcept + // { + // auto d = _den * i; + // return Fraction(_num, d); + // } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator+=(const Fraction& frac) -> Fraction& { + return *this = *this + frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator-=(const Fraction& frac) -> Fraction& { + return *this = *this - frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator*=(const Fraction& frac) -> Fraction& { + return *this = *this * frac; + } + + /*! + * @brief + * + * @param[in] frac + * @return Fraction + */ + constexpr auto operator/=(const Fraction& frac) -> Fraction& { + return *this = *this / frac; + } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator+=(const Z& i) -> Fraction& { return *this = *this + i; } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator-=(const Z& i) -> Fraction& { return *this = *this - i; } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator*=(const Z& i) -> Fraction& { + const auto common = gcd(i, this->_den); + if (common == Z(1)) { + this->_num *= i; + } + // else if (common == Z(0)) [[unlikely]] // both i and den are zero + // { + // this->_num = Z(0); + // } + else { + this->_num *= (i / common); + this->_den /= common; + } + return *this; + } + + /*! + * @brief + * + * @param[in] i + * @return Fraction + */ + constexpr auto operator/=(const Z& i) -> Fraction& { + const auto common = gcd(this->_num, i); + if (common == Z(1)) { + this->_den *= i; + } + // else if (common == Z(0)) [[unlikely]] // both i and num are zero + // { + // this->_den = Z(0); + // } + else { + this->_den *= (i / common); + this->_num /= common; + } + return *this; + } + + /*! + * @brief Three way comparison + * + * @param[in] frac + * @return auto + */ + template constexpr auto cmp(const Fraction& frac) const -> Fraction& { + if (this->_den == frac._den) { + return (this->_num - frac._num) * this->_den; + } + return this->_num * frac._den - this->_den * frac._num; + } + + template constexpr auto operator==(const Fraction& rhs) const -> bool { + if (this->_den == rhs._den) { + return this->_num == rhs._num; + } + + return this->_num * rhs._den == this->_den * rhs._num; + } + + template constexpr auto operator<(const Fraction& rhs) const -> bool { + if (this->_den == rhs._den) { + return this->_num < rhs._num; + } + + return this->_num * rhs._den < this->_den * rhs._num; + } + + /** + * @brief + * + */ + constexpr auto operator==(const Z& rhs) const -> bool { + return this->_den == Z(1) && this->_num == rhs; + } + + /** + * @brief + * + */ + constexpr auto operator<(const Z& rhs) const -> bool { + return this->_num < this->_den * rhs; + } + + /** + * @brief + * + */ + constexpr auto operator>(const Z& rhs) const -> bool { + return this->_num > this->_den * rhs; + } + + // /*! + // * @brief + // * + // * @return double + // */ + // constexpr explicit operator double()) + // { + // return double(_num) / _den; + // } + + // /** + // * @brief + // * + // */ + // friend constexpr bool operator<(const Z& lhs, const Fraction& rhs)) + // { + // return lhs * rhs.den() < rhs.num(); + // } + }; /*! * @brief * - * @param[in] i - * @return Fraction + * @param[in] c + * @param[in] frac + * @return Fraction */ - constexpr auto operator+(const Z& i) const -> Fraction - { - auto n = this->_num + this->_den * i; - return Fraction(std::move(n), this->_den); + template constexpr auto operator+(const Z& c, const Fraction& frac) + -> Fraction { + return frac + c; } /*! * @brief * - * @param[in] i - * @return Fraction + * @param[in] c + * @param[in] frac + * @return Fraction */ - constexpr auto operator-(const Z& i) const -> Fraction - { - return *this + (-i); + template constexpr auto operator-(const Z& c, const Fraction& frac) + -> Fraction { + return c + (-frac); } // /*! // * @brief // * - // * @param[in] i - // * @return Fraction - // */ - // constexpr Fraction operator*(const Z& i) const noexcept - // { - // auto n = _num * i; - // return Fraction(n, _den); - // } - - // /*! - // * @brief - // * - // * @param[in] i - // * @return Fraction + // * @param[in] c + // * @param[in] frac + // * @return Fraction // */ - // constexpr Fraction operator/(const Z& i) const noexcept + // template + // constexpr Fraction operator*(const Z& c, const Fraction& frac) // { - // auto d = _den * i; - // return Fraction(_num, d); + // return frac * c; // } /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction - */ - constexpr auto operator+=(const Fraction& frac) -> Fraction& - { - return *this = *this + frac; - } - - /*! - * @brief - * - * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator-=(const Fraction& frac) -> Fraction& - { - return *this = *this - frac; + template constexpr auto operator+(int&& c, const Fraction& frac) + -> Fraction { + return frac + c; } /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator*=(const Fraction& frac) -> Fraction& - { - return *this = *this * frac; + template constexpr auto operator-(int&& c, const Fraction& frac) + -> Fraction { + return (-frac) + c; } /*! * @brief * + * @param[in] c * @param[in] frac - * @return Fraction + * @return Fraction */ - constexpr auto operator/=(const Fraction& frac) -> Fraction& - { - return *this = *this / frac; + template constexpr auto operator*(int&& c, const Fraction& frac) + -> Fraction { + return frac * c; } /*! * @brief * - * @param[in] i - * @return Fraction - */ - constexpr auto operator+=(const Z& i) -> Fraction& - { - return *this = *this + i; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator-=(const Z& i) -> Fraction& - { - return *this = *this - i; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator*=(const Z& i) -> Fraction& - { - const auto common = gcd(i, this->_den); - if (common == Z(1)) - { - this->_num *= i; - } - // else if (common == Z(0)) [[unlikely]] // both i and den are zero - // { - // this->_num = Z(0); - // } - else - { - this->_num *= (i / common); - this->_den /= common; - } - return *this; - } - - /*! - * @brief - * - * @param[in] i - * @return Fraction - */ - constexpr auto operator/=(const Z& i) -> Fraction& - { - const auto common = gcd(this->_num, i); - if (common == Z(1)) - { - this->_den *= i; - } - // else if (common == Z(0)) [[unlikely]] // both i and num are zero - // { - // this->_den = Z(0); - // } - else - { - this->_den *= (i / common); - this->_num /= common; - } - return *this; - } - - /*! - * @brief Three way comparison - * + * @tparam _Stream + * @tparam Z + * @param[in] os * @param[in] frac - * @return auto - */ - template - constexpr auto cmp(const Fraction& frac) const -> Fraction& - { - if (this->_den == frac._den) - { - return (this->_num - frac._num) * this->_den; - } - return this->_num * frac._den - this->_den * frac._num; - } - - template - constexpr auto operator==(const Fraction& rhs) const -> bool - { - if (this->_den == rhs._den) - { - return this->_num == rhs._num; - } - - return this->_num * rhs._den == this->_den * rhs._num; - } - - template - constexpr auto operator<(const Fraction& rhs) const -> bool - { - if (this->_den == rhs._den) - { - return this->_num < rhs._num; - } - - return this->_num * rhs._den < this->_den * rhs._num; - } - - /** - * @brief - * - */ - constexpr auto operator==(const Z& rhs) const -> bool - { - return this->_den == Z(1) && this->_num == rhs; - } - - /** - * @brief - * + * @return _Stream& */ - constexpr auto operator<(const Z& rhs) const -> bool - { - return this->_num < this->_den * rhs; + template auto operator<<(_Stream& os, const Fraction& frac) + -> _Stream& { + os << frac.num() << "/" << frac.den(); + return os; } - /** - * @brief - * - */ - constexpr auto operator>(const Z& rhs) const -> bool - { - return this->_num > this->_den * rhs; - } - - // /*! - // * @brief - // * - // * @return double - // */ - // constexpr explicit operator double()) - // { - // return double(_num) / _den; - // } - - // /** - // * @brief - // * - // */ - // friend constexpr bool operator<(const Z& lhs, const Fraction& rhs)) - // { - // return lhs * rhs.den() < rhs.num(); - // } -}; - - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator+(const Z& c, const Fraction& frac) -> Fraction -{ - return frac + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator-(const Z& c, const Fraction& frac) -> Fraction -{ - return c + (-frac); -} - -// /*! -// * @brief -// * -// * @param[in] c -// * @param[in] frac -// * @return Fraction -// */ -// template -// constexpr Fraction operator*(const Z& c, const Fraction& frac) -// { -// return frac * c; -// } - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator+(int&& c, const Fraction& frac) -> Fraction -{ - return frac + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator-(int&& c, const Fraction& frac) -> Fraction -{ - return (-frac) + c; -} - -/*! - * @brief - * - * @param[in] c - * @param[in] frac - * @return Fraction - */ -template -constexpr auto operator*(int&& c, const Fraction& frac) -> Fraction -{ - return frac * c; -} - -/*! - * @brief - * - * @tparam _Stream - * @tparam Z - * @param[in] os - * @param[in] frac - * @return _Stream& - */ -template -auto operator<<(_Stream& os, const Fraction& frac) -> _Stream& -{ - os << frac.num() << "/" << frac.den(); - return os; -} - -// For template deduction -// Integral{Z} Fraction(const Z &, const Z &) noexcept -> Fraction; + // For template deduction + // Integral{Z} Fraction(const Z &, const Z &) noexcept -> Fraction; -} // namespace fun +} // namespace fun diff --git a/include/projgeom/persp_plane.hpp b/include/projgeom/persp_plane.hpp index b9e940a..8f609fb 100644 --- a/include/projgeom/persp_plane.hpp +++ b/include/projgeom/persp_plane.hpp @@ -3,181 +3,161 @@ #include "ck_plane.hpp" #include "fractions.hpp" // #include "pg_common.hpp" -#include "proj_plane.hpp" // import pg_point, involution, tri_func, - -namespace fun -{ - -/*! - * @brief - * - * @tparam P - * @tparam P::dual - */ -template -requires Projective_plane_prim // c++20 concept -class persp_euclid_plane : public ck -{ - using K = Value_type

; - - private: - P _Ire; - P _Iim; - L _l_infty; - - public: - /*! - * @brief Construct a new persp euclid plane object - * - * @param[in] Ire - * @param[in] Iim - * @param[in] l_infty - */ - constexpr persp_euclid_plane(P Ire, P Iim, L l_infty) - : _Ire {std::move(Ire)} - , _Iim {std::move(Iim)} - , _l_infty {std::move(l_infty)} - { - } - - // /*! - // * @brief Construct a new persp euclid plane object - // * - // * @param[in] Ire - // * @param[in] Iim - // * @param[in] l_infty - // */ - // constexpr persp_euclid_plane(const P &Ire, const P &Iim, const L - // &l_infty) - // : _Ire{Ire}, _Iim{Iim}, _l_infty{l_infty} {} - - // /*! - // * @brief - // * - // * @param[in] x - // * @return const L& - // */ - // constexpr const L &perp(const P &x) const { return _l_infty; } - - /*! - * @brief - * - * @return const L& - */ - [[nodiscard]] constexpr auto l_infty() const -> const L& - { - return this->_l_infty; - } - - /*! - * @brief - * - * @param[in] x - * @return P - */ - [[nodiscard]] constexpr auto perp(const L& v) const -> P - { - const auto alpha = v.dot(this->_Ire); - const auto beta = v.dot(this->_Iim); - return plucker(alpha, this->_Ire, beta, this->_Iim); - } +#include "proj_plane.hpp" // import pg_point, involution, tri_func, - /*! - * @brief - * - * @param[in] l - * @param[in] m - * @return true - * @return false - */ - [[nodiscard]] constexpr auto is_parallel(const L& l, const L& m) const - -> bool - { - return incident(this->_l_infty, l * m); - } +namespace fun { /*! * @brief * - * @param[in] a - * @param[in] b - * @return P + * @tparam P + * @tparam P::dual */ - [[nodiscard]] constexpr auto midpoint(const P& a, const P& b) const -> P - { - const auto alpha = a.dot(this->_l_infty); - const auto beta = b.dot(this->_l_infty); - return plucker(alpha, a, beta, b); - } + template + requires Projective_plane_prim // c++20 concept + class persp_euclid_plane : public ck { + using K = Value_type

; + + private: + P _Ire; + P _Iim; + L _l_infty; + + public: + /*! + * @brief Construct a new persp euclid plane object + * + * @param[in] Ire + * @param[in] Iim + * @param[in] l_infty + */ + constexpr persp_euclid_plane(P Ire, P Iim, L l_infty) + : _Ire{std::move(Ire)}, _Iim{std::move(Iim)}, _l_infty{std::move(l_infty)} {} + + // /*! + // * @brief Construct a new persp euclid plane object + // * + // * @param[in] Ire + // * @param[in] Iim + // * @param[in] l_infty + // */ + // constexpr persp_euclid_plane(const P &Ire, const P &Iim, const L + // &l_infty) + // : _Ire{Ire}, _Iim{Iim}, _l_infty{l_infty} {} + + // /*! + // * @brief + // * + // * @param[in] x + // * @return const L& + // */ + // constexpr const L &perp(const P &x) const { return _l_infty; } + + /*! + * @brief + * + * @return const L& + */ + [[nodiscard]] constexpr auto l_infty() const -> const L& { return this->_l_infty; } + + /*! + * @brief + * + * @param[in] x + * @return P + */ + [[nodiscard]] constexpr auto perp(const L& v) const -> P { + const auto alpha = v.dot(this->_Ire); + const auto beta = v.dot(this->_Iim); + return plucker(alpha, this->_Ire, beta, this->_Iim); + } - /*! - * @brief - * - * @param[in] tri - * @return auto - */ - [[nodiscard]] constexpr auto tri_midpoint(const Triple

& tri) const - { - const auto& [a1, a2, a3] = tri; + /*! + * @brief + * + * @param[in] l + * @param[in] m + * @return true + * @return false + */ + [[nodiscard]] constexpr auto is_parallel(const L& l, const L& m) const -> bool { + return incident(this->_l_infty, l * m); + } - return Triple

{this->midpoint(a1, a2), this->midpoint(a2, a3), - this->midpoint(a1, a3)}; - } + /*! + * @brief + * + * @param[in] a + * @param[in] b + * @return P + */ + [[nodiscard]] constexpr auto midpoint(const P& a, const P& b) const -> P { + const auto alpha = a.dot(this->_l_infty); + const auto beta = b.dot(this->_l_infty); + return plucker(alpha, a, beta, b); + } - /*! - * @brief - * - * @param[in] x - * @return K - */ - [[nodiscard]] constexpr auto omega(const P& x) const -> K - { - return sq(x.dot(this->_l_infty)); - } + /*! + * @brief + * + * @param[in] tri + * @return auto + */ + [[nodiscard]] constexpr auto tri_midpoint(const Triple

& tri) const { + const auto& [a1, a2, a3] = tri; + + return Triple

{this->midpoint(a1, a2), this->midpoint(a2, a3), + this->midpoint(a1, a3)}; + } - /*! - * @brief - * - * @param[in] x - * @return K - */ - [[nodiscard]] constexpr auto omega(const L& x) const -> K - { - return sq(x.dot(this->_Ire)) + sq(x.dot(this->_Iim)); - } + /*! + * @brief + * + * @param[in] x + * @return K + */ + [[nodiscard]] constexpr auto omega(const P& x) const -> K { + return sq(x.dot(this->_l_infty)); + } - /*! - * @brief - * - * @param[in] a1 - * @param[in] a2 - * @return auto - */ - template - [[nodiscard]] constexpr auto measure(const _P& a1, const _P& a2) const - { - const auto omg = K(this->omega(a1 * a2)); - const auto den = K(this->omega(a1) * this->omega(a2)); - if constexpr (Integral) - { - return Fraction(omg, den); + /*! + * @brief + * + * @param[in] x + * @return K + */ + [[nodiscard]] constexpr auto omega(const L& x) const -> K { + return sq(x.dot(this->_Ire)) + sq(x.dot(this->_Iim)); } - else - { - return omg / den; + + /*! + * @brief + * + * @param[in] a1 + * @param[in] a2 + * @return auto + */ + template + [[nodiscard]] constexpr auto measure(const _P& a1, const _P& a2) const { + const auto omg = K(this->omega(a1 * a2)); + const auto den = K(this->omega(a1) * this->omega(a2)); + if constexpr (Integral) { + return Fraction(omg, den); + } else { + return omg / den; + } } - } - - // /*! - // * @brief - // * - // * @param[in] l1 - // * @param[in] l2 - // * @return auto - // */ - // constexpr auto cross_s(const L &l1, const L &l2) const { - // return 1 - this->spread(l1, l2); // ??? - // } -}; - -} // namespace fun + + // /*! + // * @brief + // * + // * @param[in] l1 + // * @param[in] l2 + // * @return auto + // */ + // constexpr auto cross_s(const L &l1, const L &l2) const { + // return 1 - this->spread(l1, l2); // ??? + // } + }; + +} // namespace fun diff --git a/include/projgeom/pg_common.hpp b/include/projgeom/pg_common.hpp index 30a4c29..bae3d67 100644 --- a/include/projgeom/pg_common.hpp +++ b/include/projgeom/pg_common.hpp @@ -4,144 +4,126 @@ #pragma once -#include "common_concepts.h" #include #include -namespace fun -{ +#include "common_concepts.h" -/*! - * @brief 1st term of Cross product - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return 1st term of Cross product - */ -template -auto cross0(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - return v[1] * w[2] - w[1] * v[2]; -} +namespace fun { -/*! - * @brief 2nd term of Cross product - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return 2nd term of Cross product - */ -template -auto cross1(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - return v[0] * w[2] - w[0] * v[2]; -} + /*! + * @brief 1st term of Cross product + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return 1st term of Cross product + */ + template auto cross0(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + return v[1] * w[2] - w[1] * v[2]; + } -/*! - * @brief 3rd term of Cross product - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return 3rd term of Cross product - */ -template -auto cross2(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - return v[0] * w[1] - w[0] * v[1]; -} + /*! + * @brief 2nd term of Cross product + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return 2nd term of Cross product + */ + template auto cross1(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + return v[0] * w[2] - w[0] * v[2]; + } -/*! - * @brief Cross product - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return Cross product - */ -template -requires ring> -auto cross(const P& v, const P& w) -> std::array, 3> -{ - return {cross0(v, w), -cross1(v, w), cross2(v, w)}; -} + /*! + * @brief 3rd term of Cross product + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return 3rd term of Cross product + */ + template auto cross2(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + return v[0] * w[1] - w[0] * v[1]; + } -/*! - * @brief Dot product - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return auto - */ -template -auto dot_c(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - const auto& [x1, y1, z1] = v; - const auto& [x2, y2, z2] = w; - return x1 * x2 + y1 * y2 + z1 * z2; -} + /*! + * @brief Cross product + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return Cross product + */ + template + requires ring> + auto cross(const P& v, const P& w) -> std::array, 3> { + return {cross0(v, w), -cross1(v, w), cross2(v, w)}; + } -/*! - * @brief generic Plucker function - * - * @tparam _K data type - * @param[in] ld lamda - * @param[in] v - * @param[in] mu - * @param[in] w - * @return lamda*v + mu*w - */ -template -auto plucker_c(const _T& ld, const std::array<_K, 3>& v1, const _T& mu, - const std::array<_K, 3>& v2) -> std::array<_K, 3> -{ - const auto& [x1, y1, z1] = v1; - const auto& [x2, y2, z2] = v2; - return {ld * x1 + mu * x2, ld * y1 + mu * y2, ld * z1 + mu * z2}; -} + /*! + * @brief Dot product + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return auto + */ + template auto dot_c(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + const auto& [x1, y1, z1] = v; + const auto& [x2, y2, z2] = w; + return x1 * x2 + y1 * y2 + z1 * z2; + } -/*! - * @brief dot product of the (0,1)-component of two vectors - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return auto - */ -template -auto dot1(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - return v[0] * w[0] + v[1] * w[1]; -} + /*! + * @brief generic Plucker function + * + * @tparam _K data type + * @param[in] ld lamda + * @param[in] v + * @param[in] mu + * @param[in] w + * @return lamda*v + mu*w + */ + template auto plucker_c(const _T& ld, const std::array<_K, 3>& v1, + const _T& mu, const std::array<_K, 3>& v2) + -> std::array<_K, 3> { + const auto& [x1, y1, z1] = v1; + const auto& [x2, y2, z2] = v2; + return {ld * x1 + mu * x2, ld * y1 + mu * y2, ld * z1 + mu * z2}; + } -/*! - * @brief dot product of the (0,2)-component of two vectors - * - * @tparam _K - * @param[in] v - * @param[in] w - * @return auto - */ -template -auto dot2(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K -{ - return v[0] * w[0] + v[2] * w[2]; -} + /*! + * @brief dot product of the (0,1)-component of two vectors + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return auto + */ + template auto dot1(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + return v[0] * w[0] + v[1] * w[1]; + } -/*! - * @brief Square function - * - * @tparam T data type - * @param[in] a input value - * @return a^2 - */ -template -constexpr inline auto sq(const T& a) -{ - return a * a; -} + /*! + * @brief dot product of the (0,2)-component of two vectors + * + * @tparam _K + * @param[in] v + * @param[in] w + * @return auto + */ + template auto dot2(const std::array<_K, 3>& v, const std::array<_K, 3>& w) -> _K { + return v[0] * w[0] + v[2] * w[2]; + } + + /*! + * @brief Square function + * + * @tparam T data type + * @param[in] a input value + * @return a^2 + */ + template constexpr inline auto sq(const T& a) { return a * a; } -} // namespace fun +} // namespace fun diff --git a/include/projgeom/pg_line.hpp b/include/projgeom/pg_line.hpp index 21833e7..e794539 100644 --- a/include/projgeom/pg_line.hpp +++ b/include/projgeom/pg_line.hpp @@ -11,55 +11,43 @@ #include "pg_common.hpp" #include "pg_object.hpp" -namespace fun -{ +namespace fun { -// Forward declarations. + // Forward declarations. -template -struct pg_point; - -/*! - * @brief Projective line: two dimensional subspace of K^3 - * - * @tparam _K Type of line elements - */ -template -struct pg_line : pg_object<_K, pg_point<_K>> -{ - /// Value typedef. - using _Base = pg_object<_K, pg_point<_K>>; - using _Base2 = std::array<_K, 3>; - - /*! - * @brief Construct a new pg object object - * - * @param[in] a array of coordinates - */ - constexpr explicit pg_line(const _Base2& a) - : _Base {a} - { - } + template struct pg_point; /*! - * @brief Construct a new pg_object object + * @brief Projective line: two dimensional subspace of K^3 * - * @param[in] x - * @param[in] y - * @param[in] z + * @tparam _K Type of line elements */ - constexpr pg_line(const _K& x, const _K& y, const _K& z) - : _Base {_Base2 {x, y, z}} - { + template struct pg_line : pg_object<_K, pg_point<_K>> { + /// Value typedef. + using _Base = pg_object<_K, pg_point<_K>>; + using _Base2 = std::array<_K, 3>; + + /*! + * @brief Construct a new pg object object + * + * @param[in] a array of coordinates + */ + constexpr explicit pg_line(const _Base2& a) : _Base{a} {} + + /*! + * @brief Construct a new pg_object object + * + * @param[in] x + * @param[in] y + * @param[in] z + */ + constexpr pg_line(const _K& x, const _K& y, const _K& z) : _Base{_Base2{x, y, z}} {} + }; + + /// Return meet of two lines. + template inline constexpr auto meet(const pg_line<_K>& l, const pg_line<_K>& m) + -> pg_point<_K> { + return l * m; } -}; - -/// Return meet of two lines. -template -inline constexpr auto meet(const pg_line<_K>& l, const pg_line<_K>& m) - -> pg_point<_K> -{ - return l * m; -} -} // namespace fun +} // namespace fun diff --git a/include/projgeom/pg_object.hpp b/include/projgeom/pg_object.hpp index f627632..5b316b7 100644 --- a/include/projgeom/pg_object.hpp +++ b/include/projgeom/pg_object.hpp @@ -10,175 +10,154 @@ #include "pg_common.hpp" -namespace fun -{ - -/*! - * @brief Projective object - * - * @tparam _K Type of object elements - * @tparam _dual - */ -template -class pg_object : public std::array<_K, 3> -{ - /// Value typedef. - using _Base = std::array<_K, 3>; - using _Self = pg_object<_K, _dual>; - - public: - using value_type = _K; - using dual = _dual; - - // pg_object(_Self &&) = default; - - /*! - * @brief Construct a new pg object object - * - * @param[in] a array of coordinates - */ - constexpr explicit pg_object(const _Base& a) - : _Base {a} - { - } - - /*! - * @brief Construct a new pg object - * - */ - explicit pg_object(const _Self&) = default; +namespace fun { /*! - * @brief - * - * @return _Self& - */ - auto operator=(const _Self&) -> _Self& = delete; - - /*! - * @brief Construct a new pg object - * - */ - pg_object(_Self&&) noexcept = default; - - /*! - * @brief + * @brief Projective object * - * @return _Self& + * @tparam _K Type of object elements + * @tparam _dual */ - auto operator=(_Self&&) noexcept -> _Self& = default; - - // Operators: - - /*! - * @brief Equal to - * - * @param[in] rhs - * @return true if this object is equivalent to the rhs - * @return false otherwise - */ - friend constexpr auto operator==(const _Self& lhs, const _Self& rhs) -> bool - { - if (&lhs == &rhs) - { - return true; + template class pg_object : public std::array<_K, 3> { + /// Value typedef. + using _Base = std::array<_K, 3>; + using _Self = pg_object<_K, _dual>; + + public: + using value_type = _K; + using dual = _dual; + + // pg_object(_Self &&) = default; + + /*! + * @brief Construct a new pg object object + * + * @param[in] a array of coordinates + */ + constexpr explicit pg_object(const _Base& a) : _Base{a} {} + + /*! + * @brief Construct a new pg object + * + */ + explicit pg_object(const _Self&) = default; + + /*! + * @brief + * + * @return _Self& + */ + auto operator=(const _Self&) -> _Self& = delete; + + /*! + * @brief Construct a new pg object + * + */ + pg_object(_Self&&) noexcept = default; + + /*! + * @brief + * + * @return _Self& + */ + auto operator=(_Self&&) noexcept -> _Self& = default; + + // Operators: + + /*! + * @brief Equal to + * + * @param[in] rhs + * @return true if this object is equivalent to the rhs + * @return false otherwise + */ + friend constexpr auto operator==(const _Self& lhs, const _Self& rhs) -> bool { + if (&lhs == &rhs) { + return true; + } + return cross(lhs, rhs) == _Base{_K(0), _K(0), _K(0)}; } - return cross(lhs, rhs) == _Base {_K(0), _K(0), _K(0)}; - } - /*! - * @brief Not equal to - * - * @param[in] rhs - * @return true if this object is not equivalent to the rhs - * @return false otherwise - */ - friend constexpr auto operator!=(const _Self& lhs, const _Self& rhs) -> bool - { - return !(lhs == rhs); - } + /*! + * @brief Not equal to + * + * @param[in] rhs + * @return true if this object is not equivalent to the rhs + * @return false otherwise + */ + friend constexpr auto operator!=(const _Self& lhs, const _Self& rhs) -> bool { + return !(lhs == rhs); + } - /*! - * @brief Equal to - * - * @param[in] rhs - * @return true if this object is equivalent to the rhs - * @return false otherwise - */ - [[nodiscard]] constexpr auto is_NaN() const -> bool - { - const _Base& base = *this; - return base == _Base {_K(0), _K(0), _K(0)}; - } + /*! + * @brief Equal to + * + * @param[in] rhs + * @return true if this object is equivalent to the rhs + * @return false otherwise + */ + [[nodiscard]] constexpr auto is_NaN() const -> bool { + const _Base& base = *this; + return base == _Base{_K(0), _K(0), _K(0)}; + } + /*! + * @brief the dot product + * + * @param[in] l + * @return _K + */ + [[nodiscard]] constexpr auto dot(const dual& l) const -> _K { return fun::dot_c(*this, l); } + + /*! + * @brief Generate a new line not incident with p + * + * @return dual + */ + [[nodiscard]] constexpr auto aux() const -> dual { return dual(*this); } + + /*! + * @brief Join or meet + * + * @param[in] rhs + * @return true if this point is equivalent to the rhs + * @return false otherwise + */ + friend constexpr auto operator*(const _Self& lhs, const _Self& rhs) -> dual { + return dual(cross(lhs, rhs)); + } + }; /*! - * @brief the dot product + * @brief * - * @param[in] l - * @return _K + * @tparam P + * @tparam Value_type

+ * @param[in] lda1 + * @param[in] p + * @param[in] mu1 + * @param[in] q + * @return P */ - [[nodiscard]] constexpr auto dot(const dual& l) const -> _K - { - return fun::dot_c(*this, l); + template > + inline constexpr auto plucker(const _K& ld1, const P& p, const _K& mu1, const P& q) -> P { + return P{plucker_c(ld1, p, mu1, q)}; } /*! - * @brief Generate a new line not incident with p + * @brief * - * @return dual + * @tparam _K + * @tparam _dual + * @tparam _Stream + * @param[in] os + * @param[in] p + * @return _Stream& */ - [[nodiscard]] constexpr auto aux() const -> dual - { - return dual(*this); + template + auto operator<<(_Stream& os, const pg_object<_K, _dual>& p) -> _Stream& { + os << '(' << p[0] << ':' << p[1] << ':' << p[2] << ')'; + return os; } - /*! - * @brief Join or meet - * - * @param[in] rhs - * @return true if this point is equivalent to the rhs - * @return false otherwise - */ - friend constexpr auto operator*(const _Self& lhs, const _Self& rhs) -> dual - { - return dual(cross(lhs, rhs)); - } -}; - -/*! - * @brief - * - * @tparam P - * @tparam Value_type

- * @param[in] lda1 - * @param[in] p - * @param[in] mu1 - * @param[in] q - * @return P - */ -template > -inline constexpr auto plucker( - const _K& ld1, const P& p, const _K& mu1, const P& q) -> P -{ - return P {plucker_c(ld1, p, mu1, q)}; -} - -/*! - * @brief - * - * @tparam _K - * @tparam _dual - * @tparam _Stream - * @param[in] os - * @param[in] p - * @return _Stream& - */ -template -auto operator<<(_Stream& os, const pg_object<_K, _dual>& p) -> _Stream& -{ - os << '(' << p[0] << ':' << p[1] << ':' << p[2] << ')'; - return os; -} - -} // namespace fun +} // namespace fun diff --git a/include/projgeom/pg_point.hpp b/include/projgeom/pg_point.hpp index 440b894..5a99b09 100644 --- a/include/projgeom/pg_point.hpp +++ b/include/projgeom/pg_point.hpp @@ -11,82 +11,70 @@ #include "pg_common.hpp" #include "pg_object.hpp" -namespace fun -{ +namespace fun { -// Forward declarations. -template -struct pg_line; + // Forward declarations. + template struct pg_line; -template -struct pg_point : pg_object<_K, pg_line<_K>> -{ - /// Value typedef. - using _Base = pg_object<_K, pg_line<_K>>; - using _Base2 = std::array<_K, 3>; - // using value_type = _K; + template struct pg_point : pg_object<_K, pg_line<_K>> { + /// Value typedef. + using _Base = pg_object<_K, pg_line<_K>>; + using _Base2 = std::array<_K, 3>; + // using value_type = _K; - /*! - * @brief Construct a new pg point object - * - */ - explicit pg_point(const pg_point<_K>&) = default; + /*! + * @brief Construct a new pg point object + * + */ + explicit pg_point(const pg_point<_K>&) = default; - /*! - * @brief Construct a new pg point object - * - */ - pg_point(pg_point<_K>&&) noexcept = default; + /*! + * @brief Construct a new pg point object + * + */ + pg_point(pg_point<_K>&&) noexcept = default; - /*! - * @brief - * - * @return pg_point<_K>& - */ - auto operator=(const pg_point<_K>&) -> pg_point<_K>& = delete; + /*! + * @brief + * + * @return pg_point<_K>& + */ + auto operator=(const pg_point<_K>&) -> pg_point<_K>& = delete; - /*! - * @brief - * - * @return pg_point<_K>& - */ - auto operator=(pg_point<_K>&&) noexcept -> pg_point<_K>& = default; + /*! + * @brief + * + * @return pg_point<_K>& + */ + auto operator=(pg_point<_K>&&) noexcept -> pg_point<_K>& = default; - /*! - * @brief Construct a new pg object object - * - * @param[in] a array of coordinates - */ - constexpr explicit pg_point(const _Base2& a) - : _Base {a} - { - } + /*! + * @brief Construct a new pg object object + * + * @param[in] a array of coordinates + */ + constexpr explicit pg_point(const _Base2& a) : _Base{a} {} + + /*! + * @brief Construct a new pg_object object + * + * @param[in] x + * @param[in] y + * @param[in] z + */ + constexpr pg_point(const _K& x, const _K& y, const _K& z) : _Base{_Base2{x, y, z}} {} + }; /*! - * @brief Construct a new pg_object object + * @brief Return join of two points. * - * @param[in] x - * @param[in] y - * @param[in] z + * @param[in] p + * @param[in] q + * @return pg_line<_K> */ - constexpr pg_point(const _K& x, const _K& y, const _K& z) - : _Base {_Base2 {x, y, z}} - { + template inline constexpr auto join(const pg_point<_K>& p, const pg_point<_K>& q) + -> pg_line<_K> { + return p * q; } -}; - -/*! - * @brief Return join of two points. - * - * @param[in] p - * @param[in] q - * @return pg_line<_K> - */ -template -inline constexpr auto join(const pg_point<_K>& p, const pg_point<_K>& q) - -> pg_line<_K> -{ - return p * q; -} -} // namespace fun +} // namespace fun diff --git a/include/projgeom/proj_plane.hpp b/include/projgeom/proj_plane.hpp index 98ce3e9..febd2d2 100644 --- a/include/projgeom/proj_plane.hpp +++ b/include/projgeom/proj_plane.hpp @@ -1,9 +1,10 @@ #pragma once -#include "proj_plane_concepts.h" #include #include +#include "proj_plane_concepts.h" + /*! @file include/proj_plane.hpp * This is a C++ Library header. */ @@ -12,280 +13,250 @@ @todo: projectivity >= **/ -namespace fun -{ - -/*! - * @brief - * - * @param[in] p - * @param[in] l - * @return true - * @return false - */ -template -requires Projective_plane -constexpr auto incident(const P& p, const L& l) -> bool -{ - return p.dot(l) == Value_type

(0); -} - - -/** - * @brief Coincident - * - * @tparam[in] L Line - * @tparam[in] Args points - * @return true if points are conincident (on a line l) - * @return false otherwise - */ -template -requires(Projective_plane_prim && ...) -constexpr auto coincident( - const L& l, const Args&... r) -> bool -{ - return (incident(r, l) && ...); -} - -template -using Triple = std::tuple; - -/*! - * @brief - * - * @param[in] tri - * @return auto - */ -template -constexpr auto tri_dual(const Triple

& tri) - -{ - const auto& [a1, a2, a3] = tri; - assert(!coincident(a2 * a3, a1)); - return std::tuple {a2 * a3, a1 * a3, a1 * a2}; -} - -/*! - * @brief - * - * @param[in] func - * @param[in] tri - * @return auto - */ -template -constexpr auto tri_func(Fn&& func, const Triple

& tri) - -{ - const auto& [a1, a2, a3] = tri; - return std::tuple {func(a2, a3), func(a1, a3), func(a1, a2)}; -} - -/*! - * @brief return whether two triangles are perspective - * - * @param[in] tri1 - * @param[in] tri2 - * @return true - * @return false - */ -template -constexpr auto persp(const Triple

& tri1, const Triple

& tri2) -> bool -{ - const auto& [A, B, C] = tri1; - const auto& [D, E, F] = tri2; - const auto O = (A * D) * (B * E); - return incident(O, C * F); -} - +namespace fun { -/*! - * @brief - * - * @tparam P - * @param[in] A - * @param[in] B - * @param[in] C - * @return constexpr P - */ -template -constexpr auto harm_conj(const P& A, const P& B, const P& C) -> P -{ - assert(incident(A * B, C)); - const auto lC = C * (A * B).aux(); - return plucker(B.dot(lC), A, A.dot(lC), B); -} + /*! + * @brief + * + * @param[in] p + * @param[in] l + * @return true + * @return false + */ + template + requires Projective_plane + constexpr auto incident(const P& p, const L& l) -> bool { return p.dot(l) == Value_type

(0); } + /** + * @brief Coincident + * + * @tparam[in] L Line + * @tparam[in] Args points + * @return true if points are conincident (on a line l) + * @return false otherwise + */ + template + requires(Projective_plane_prim&&...) constexpr auto coincident(const L& l, + const Args&... r) + -> bool { + return (incident(r, l) && ...); + } -/*! - * @brief - * - * @tparam P - * @param[in] A - * @param[in] B - * @param[in] C - * @return constexpr P - */ -template -constexpr auto harm_conj(const _P& A, const _P& B, const _P& C) -> _P -{ - assert(incident(A * B, C)); - const auto AB = A * B; - const auto P = AB.aux(); - const auto R = P.aux2(C); - const auto S = (A * R) * (B * P); - const auto Q = (B * R) * (A * P); - return (Q * S) * AB; -} + template using Triple = std::tuple; -/*! - * @brief - * - * @param[in] A - * @param[in] B - * @param[in] C - * @param[in] D - * @return constexpr auto - * - */ -template -constexpr auto is_harmonic(const P& A, const P& B, const P& C, const P& D) - -> bool -{ - return harm_conj(A, B, C) == D; -} + /*! + * @brief + * + * @param[in] tri + * @return auto + */ + template constexpr auto tri_dual(const Triple

& tri) + { + const auto& [a1, a2, a3] = tri; + assert(!coincident(a2 * a3, a1)); + return std::tuple{a2 * a3, a1 * a3, a1 * a2}; + } -/** - * @brief - * - * @tparam P - * @tparam L - */ -template -requires Projective_plane -class involution -{ - using K = Value_type

; + /*! + * @brief + * + * @param[in] func + * @param[in] tri + * @return auto + */ + template + constexpr auto tri_func(Fn&& func, const Triple

& tri) - private: - L _m; - P _o; - K _c; + { + const auto& [a1, a2, a3] = tri; + return std::tuple{func(a2, a3), func(a1, a3), func(a1, a2)}; + } - public: /*! - * @brief Construct a new involution object + * @brief return whether two triangles are perspective * - * @param[in] m - * @param[in] o + * @param[in] tri1 + * @param[in] tri2 + * @return true + * @return false */ - constexpr involution(L m, P o) // input mirror and center - : _m {std::move(m)} - , _o {std::move(o)} - , _c {_m.dot(_o)} - { + template + constexpr auto persp(const Triple

& tri1, const Triple

& tri2) -> bool { + const auto& [A, B, C] = tri1; + const auto& [D, E, F] = tri2; + const auto O = (A * D) * (B * E); + return incident(O, C * F); } /*! * @brief * - * @param[in] p - * @return P + * @tparam P + * @param[in] A + * @param[in] B + * @param[in] C + * @return constexpr P */ - constexpr auto operator()(const P& p) const -> P - { - return plucker(this->_c, p, K(-2 * p.dot(this->_m)), this->_o); + template constexpr auto harm_conj(const P& A, const P& B, const P& C) + -> P { + assert(incident(A * B, C)); + const auto lC = C * (A * B).aux(); + return plucker(B.dot(lC), A, A.dot(lC), B); } /*! * @brief * - * @param[in] p - * @return P + * @tparam P + * @param[in] A + * @param[in] B + * @param[in] C + * @return constexpr P */ - constexpr auto operator()(const L& l) const -> L - { - return plucker(this->_c, l, K(-2 * l.dot(this->_o)), this->_m); + template + constexpr auto harm_conj(const _P& A, const _P& B, const _P& C) -> _P { + assert(incident(A * B, C)); + const auto AB = A * B; + const auto P = AB.aux(); + const auto R = P.aux2(C); + const auto S = (A * R) * (B * P); + const auto Q = (B * R) * (A * P); + return (Q * S) * AB; } -}; + /*! + * @brief + * + * @param[in] A + * @param[in] B + * @param[in] C + * @param[in] D + * @return constexpr auto + * + */ + template + constexpr auto is_harmonic(const P& A, const P& B, const P& C, const P& D) -> bool { + return harm_conj(A, B, C) == D; + } -/** - * @brief - * - * @tparam P - * @tparam L - */ -template -requires Projective_plane_generic -class involution_generic -{ - private: - L _m; - P _o; + /** + * @brief + * + * @tparam P + * @tparam L + */ + template + requires Projective_plane + class involution { + using K = Value_type

; + + private: + L _m; + P _o; + K _c; + + public: + /*! + * @brief Construct a new involution object + * + * @param[in] m + * @param[in] o + */ + constexpr involution(L m, P o) // input mirror and center + : _m{std::move(m)}, _o{std::move(o)}, _c{_m.dot(_o)} {} + + /*! + * @brief + * + * @param[in] p + * @return P + */ + constexpr auto operator()(const P& p) const -> P { + return plucker(this->_c, p, K(-2 * p.dot(this->_m)), this->_o); + } + + /*! + * @brief + * + * @param[in] p + * @return P + */ + constexpr auto operator()(const L& l) const -> L { + return plucker(this->_c, l, K(-2 * l.dot(this->_o)), this->_m); + } + }; + + /** + * @brief + * + * @tparam P + * @tparam L + */ + template + requires Projective_plane_generic + class involution_generic { + private: + L _m; + P _o; + + public: + /*! + * @brief Construct a new involution object + * + * @param[in] m + * @param[in] o + */ + constexpr involution_generic(L m, P o) // input mirror and center + : _m{std::move(m)}, _o{std::move(o)} {} + + /*! + * @brief + * + * @param[in] p + * @return P + */ + constexpr auto operator()(const P& p) const -> P { + auto po = p * this->_o; + auto B = po * this->_m; + return harm_conj(this->_o, B, p); + } + }; - public: /*! - * @brief Construct a new involution object + * @brief Check Pappus Theorem * - * @param[in] m - * @param[in] o + * @tparam P + * @tparam L + * @param[in] co1 + * @param[in] co2 */ - constexpr involution_generic(L m, P o) // input mirror and center - : _m {std::move(m)} - , _o {std::move(o)} + template + void check_pappus(const Triple

& co1, const Triple

& co2) + { + const auto& [A, B, C] = co1; + const auto& [D, E, F] = co2; + + const auto G = (A * E) * (B * D); + const auto H = (A * F) * (C * D); + const auto I = (B * F) * (C * E); + assert(coincident(G, H, I)); } /*! * @brief * - * @param[in] p - * @return P + * @param[in] tri1 + * @param[in] tri2 */ - constexpr auto operator()(const P& p) const -> P - { - auto po = p * this->_o; - auto B = po * this->_m; - return harm_conj(this->_o, B, p); + template + void check_desargue(const Triple

& tri1, const Triple

& tri2) { + const auto trid1 = tri_dual(tri1); + const auto trid2 = tri_dual(tri2); + const auto b1 = persp(tri1, tri2); + const auto b2 = persp(trid1, trid2); + assert((b1 && b2) || (!b1 && !b2)); } -}; - -/*! - * @brief Check Pappus Theorem - * - * @tparam P - * @tparam L - * @param[in] co1 - * @param[in] co2 - */ -template -void check_pappus(const Triple

& co1, const Triple

& co2) - -{ - const auto& [A, B, C] = co1; - const auto& [D, E, F] = co2; - - const auto G = (A * E) * (B * D); - const auto H = (A * F) * (C * D); - const auto I = (B * F) * (C * E); - assert(coincident(G, H, I)); -} - -/*! - * @brief - * - * @param[in] tri1 - * @param[in] tri2 - */ -template -void check_desargue(const Triple

& tri1, const Triple

& tri2) -{ - const auto trid1 = tri_dual(tri1); - const auto trid2 = tri_dual(tri2); - const auto b1 = persp(tri1, tri2); - const auto b2 = persp(trid1, trid2); - assert((b1 && b2) || (!b1 && !b2)); -} -} // namespace fun +} // namespace fun diff --git a/include/projgeom/proj_plane_concepts.h b/include/projgeom/proj_plane_concepts.h index 70d4299..3d25ec5 100644 --- a/include/projgeom/proj_plane_concepts.h +++ b/include/projgeom/proj_plane_concepts.h @@ -10,158 +10,150 @@ * @todo: projectivity >= */ -namespace fun -{ - -/*! - * @brief Projective plane Concept (half) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_prim_h = std::equality_comparable

&& requires( - const P& p, const P& q, const L& l) -{ - { incident(p, l) } -> std::convertible_to; // incidence - { p * q } -> std::convertible_to; // join or meet - // { p.aux() } -> std::convertible_to; // line not incident with p - // { p.aux2(q) } -> std::convertible_to

; // point r on p * q, r != p and r != q -}; - -/*! - * @brief Projective plane Concept (full) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_prim = - Projective_plane_prim_h && Projective_plane_prim_h; - -/*! - * @brief Shorthand Notation of Projective_plane - * - * @tparam P Point - */ -template -concept Projective_plane_prim2 = - Projective_plane_prim>; // Make the compiler - // happy - -/*! - * @brief Projective plane Concept (full) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_generic_h = - Projective_plane_prim_h && requires(const P& p, const P& q) -{ - { p.aux() } -> std::convertible_to; // line not incident with p - { p.aux2(q) } -> std::convertible_to

; // point r on p * q, r != p and r != q -}; - -/*! - * @brief Projective plane Concept (full) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_generic = - Projective_plane_generic_h && Projective_plane_generic_h; - - -/*! - * @brief Shorthand Notation of Projective_plane - * - * @tparam P Point - */ -template -concept Projective_plane_generic2 = - Projective_plane_generic>; // Make the compiler - // happy - -/*! - * @brief Projective plane Concept (half) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_h = std::equality_comparable

&& requires( - const P& p, const P& q, const L& l, const Value_type

& a) -{ - typename Value_type

; - // { P(p) } -> P; // copyable - // { incident(p, l) } -> bool; // incidence - { p * q } -> std::convertible_to; // join or meet - { p.dot(l) } -> std::convertible_to>; // for measurement - { p.aux() } -> std::convertible_to; // line not incident with p - { plucker(a, p, a, q) } -> std::convertible_to

; // module computation -}; - -/*! - * @brief Projective plane Concept (full) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane = Projective_plane_h&& Projective_plane_h; - -/* -axiom(P p, P q, P r, L l) { - l == L{p, q} => I(p, l) and I(q, l); -} -*/ - - -/*! - * @brief Shorthand Notation of Projective_plane - * - * @tparam P Point - */ -template -concept Projective_plane2 = - Projective_plane>; // Make the compiler happy - -/*! - * @brief Projective plane Concept (half) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_coord_h = Projective_plane_h && - requires( - const P& p, size_t idx) -{ - typename Value_type

; - - { p[idx] } -> std::convertible_to>; // for coordinate acess -}; - -/*! - * @brief Projective plane Concept (full) - * - * @tparam P Point - * @tparam L Line - */ -template -concept Projective_plane_coord = - Projective_plane_coord_h&& Projective_plane_coord_h; - -/*! - * @brief Shorthand Notation of Projective_plane - * - * @tparam P Point - */ -template -concept Projective_plane_coord2 = - Projective_plane_coord>; // Make the compiler - // happy - -} // namespace fun +namespace fun { + + /*! + * @brief Projective plane Concept (half) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_prim_h + = std::equality_comparable

&& requires(const P& p, const P& q, const L& l) { + { incident(p, l) } -> std::convertible_to; // incidence + { p* q } -> std::convertible_to; // join or meet + // { p.aux() } -> std::convertible_to; // line not incident with p + // { p.aux2(q) } -> std::convertible_to

; // point r on p * q, r != p and r != q + }; + + /*! + * @brief Projective plane Concept (full) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_prim = Projective_plane_prim_h && Projective_plane_prim_h; + + /*! + * @brief Shorthand Notation of Projective_plane + * + * @tparam P Point + */ + template + concept Projective_plane_prim2 + = Projective_plane_prim>; // Make the compiler + // happy + + /*! + * @brief Projective plane Concept (full) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_generic_h + = Projective_plane_prim_h && requires(const P& p, const P& q) { + { p.aux() } -> std::convertible_to; // line not incident with p + { p.aux2(q) } -> std::convertible_to

; // point r on p * q, r != p and r != q + }; + + /*! + * @brief Projective plane Concept (full) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_generic + = Projective_plane_generic_h && Projective_plane_generic_h; + + /*! + * @brief Shorthand Notation of Projective_plane + * + * @tparam P Point + */ + template + concept Projective_plane_generic2 + = Projective_plane_generic>; // Make the compiler + // happy + + /*! + * @brief Projective plane Concept (half) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_h + = std::equality_comparable

&& requires(const P& p, const P& q, const L& l, + const Value_type

& a) { + typename Value_type

; + // { P(p) } -> P; // copyable + // { incident(p, l) } -> bool; // incidence + { p* q } -> std::convertible_to; // join or meet + { p.dot(l) } -> std::convertible_to>; // for measurement + { p.aux() } -> std::convertible_to; // line not incident with p + { plucker(a, p, a, q) } -> std::convertible_to

; // module computation + }; + + /*! + * @brief Projective plane Concept (full) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane = Projective_plane_h && Projective_plane_h; + + /* + axiom(P p, P q, P r, L l) { + l == L{p, q} => I(p, l) and I(q, l); + } + */ + + /*! + * @brief Shorthand Notation of Projective_plane + * + * @tparam P Point + */ + template + concept Projective_plane2 + = Projective_plane>; // Make the compiler happy + + /*! + * @brief Projective plane Concept (half) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_coord_h + = Projective_plane_h && requires(const P& p, size_t idx) { + typename Value_type

; + + { p[idx] } -> std::convertible_to>; // for coordinate acess + }; + + /*! + * @brief Projective plane Concept (full) + * + * @tparam P Point + * @tparam L Line + */ + template + concept Projective_plane_coord + = Projective_plane_coord_h && Projective_plane_coord_h; + + /*! + * @brief Shorthand Notation of Projective_plane + * + * @tparam P Point + */ + template + concept Projective_plane_coord2 + = Projective_plane_coord>; // Make the compiler + // happy + +} // namespace fun diff --git a/include/projgeom/proj_plane_measure.hpp b/include/projgeom/proj_plane_measure.hpp index de73708..8e36d51 100644 --- a/include/projgeom/proj_plane_measure.hpp +++ b/include/projgeom/proj_plane_measure.hpp @@ -11,119 +11,107 @@ @todo: projectivity >= **/ -namespace fun -{ +namespace fun { -/*! - * @brief - * - * @tparam K - * @param[in] a - * @param[in] b - * @param[in] c - * @param[in] d - * @return auto - */ -template -constexpr auto ratio_ratio(const K& a, const K& b, const K& c, const K& d) -{ - if constexpr (Integral) - { - return Fraction(a, b) / Fraction(c, d); + /*! + * @brief + * + * @tparam K + * @param[in] a + * @param[in] b + * @param[in] c + * @param[in] d + * @return auto + */ + template constexpr auto ratio_ratio(const K& a, const K& b, const K& c, const K& d) { + if constexpr (Integral) { + return Fraction(a, b) / Fraction(c, d); + } else { + return (a * d) / (b * c); + } } - else - { - return (a * d) / (b * c); - } -} -/*! - * @brief Cross Ratio - * - * @tparam P - * @tparam L - * @param[in] A point \in P - * @param[in] B point \in P - * @param[in] l line \in P - * @param[in] m line \in P - * @return cross ratio R(A,B;l,m) - * - * @todo rewrite by projecting to the y-axis first [:2] - */ -template -requires Projective_plane -constexpr auto x_ratio(const P& A, const P& B, const L& l, const L& m) -{ - return ratio_ratio(A.dot(l), A.dot(m), B.dot(l), B.dot(m)); -} + /*! + * @brief Cross Ratio + * + * @tparam P + * @tparam L + * @param[in] A point \in P + * @param[in] B point \in P + * @param[in] l line \in P + * @param[in] m line \in P + * @return cross ratio R(A,B;l,m) + * + * @todo rewrite by projecting to the y-axis first [:2] + */ + template + requires Projective_plane + constexpr auto x_ratio(const P& A, const P& B, const L& l, const L& m) { + return ratio_ratio(A.dot(l), A.dot(m), B.dot(l), B.dot(m)); + } -/*! - * @brief - * - * @param[in] A - * @param[in] B - * @param[in] C - * @param[in] D - * @return constexpr auto - */ -template -constexpr auto R(const P& A, const P& B, const P& C, const P& D) + /*! + * @brief + * + * @param[in] A + * @param[in] B + * @param[in] C + * @param[in] D + * @return constexpr auto + */ + template + constexpr auto R(const P& A, const P& B, const P& C, const P& D) -{ - using K = Value_type

; - if (cross0(A, B) != K(0)) - { // Project points to yz-plane - return R0(A, B, C, D); + { + using K = Value_type

; + if (cross0(A, B) != K(0)) { // Project points to yz-plane + return R0(A, B, C, D); + } + // Project points to xz-plane + return R1(A, B, C, D); } - // Project points to xz-plane - return R1(A, B, C, D); -} + /*! + * @brief + * + * @param[in] A + * @param[in] B + * @param[in] C + * @param[in] D + * @return constexpr auto + */ + template + constexpr auto R(const P& A, const P& B, const P& C, const P& D) { + const auto O = (C * D).aux(); + return x_ratio(A, B, O * C, O * D); + } -/*! - * @brief - * - * @param[in] A - * @param[in] B - * @param[in] C - * @param[in] D - * @return constexpr auto - */ -template -constexpr auto R(const P& A, const P& B, const P& C, const P& D) -{ - const auto O = (C * D).aux(); - return x_ratio(A, B, O * C, O * D); -} - -/*! - * @brief - * - * @param[in] A - * @param[in] B - * @param[in] C - * @param[in] D - * @return constexpr auto - */ -template -constexpr auto R0(const P& A, const P& B, const P& C, const P& D) -{ - return ratio_ratio(cross0(A, C), cross0(A, D), cross0(B, C), cross0(B, D)); -} + /*! + * @brief + * + * @param[in] A + * @param[in] B + * @param[in] C + * @param[in] D + * @return constexpr auto + */ + template + constexpr auto R0(const P& A, const P& B, const P& C, const P& D) { + return ratio_ratio(cross0(A, C), cross0(A, D), cross0(B, C), cross0(B, D)); + } -/*! - * @brief - * - * @param[in] A - * @param[in] B - * @param[in] C - * @param[in] D - * @return constexpr auto - */ -template -constexpr auto R1(const P& A, const P& B, const P& C, const P& D) -{ - return ratio_ratio(cross1(A, C), cross1(A, D), cross1(B, C), cross1(B, D)); -} + /*! + * @brief + * + * @param[in] A + * @param[in] B + * @param[in] C + * @param[in] D + * @return constexpr auto + */ + template + constexpr auto R1(const P& A, const P& B, const P& C, const P& D) { + return ratio_ratio(cross1(A, C), cross1(A, D), cross1(B, C), cross1(B, D)); + } -} // namespace fun +} // namespace fun diff --git a/standalone/CMakeLists.txt b/standalone/CMakeLists.txt index cccc1a6..7cc2708 100644 --- a/standalone/CMakeLists.txt +++ b/standalone/CMakeLists.txt @@ -16,6 +16,8 @@ CPMAddPackage( OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES" ) +include(../specific.cmake) + CPMAddPackage(NAME ProjGeom SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) # ---- Create standalone executable ---- @@ -26,4 +28,4 @@ add_executable(ProjGeomStandalone ${sources}) set_target_properties(ProjGeomStandalone PROPERTIES CXX_STANDARD 20 OUTPUT_NAME "ProjGeom") -target_link_libraries(ProjGeomStandalone ProjGeom::ProjGeom cxxopts) +target_link_libraries(ProjGeomStandalone ProjGeom::ProjGeom cxxopts Boost::boost) diff --git a/standalone/source/main.cpp b/standalone/source/main.cpp index 71eeab5..720e56a 100644 --- a/standalone/source/main.cpp +++ b/standalone/source/main.cpp @@ -46,8 +46,8 @@ auto main(int argc, char** argv) -> int { return 1; } - projgeom::ProjGeom projgeom(name); - std::cout << projgeom.greet(langIt->second) << std::endl; + // projgeom::ProjGeom projgeom(name); + // std::cout << projgeom.greet(langIt->second) << std::endl; return 0; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index daed81f..f255b7b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,7 +30,7 @@ endif() file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) add_executable(ProjGeomTests ${sources}) -target_link_libraries(ProjGeomTests doctest::doctest ProjGeom::ProjGeom) +target_link_libraries(ProjGeomTests doctest::doctest ProjGeom::ProjGeom Boost::boost) set_target_properties(ProjGeomTests PROPERTIES CXX_STANDARD 20) # enable compiler warnings diff --git a/test/source/test_ck_plane.cpp b/test/source/test_ck_plane.cpp index 1d28d87..4ed4d00 100644 --- a/test/source/test_ck_plane.cpp +++ b/test/source/test_ck_plane.cpp @@ -1,13 +1,15 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ +#include + +#include + #include "projgeom/ck_plane.hpp" #include "projgeom/persp_plane.hpp" #include "projgeom/pg_common.hpp" #include "projgeom/pg_line.hpp" #include "projgeom/pg_point.hpp" -#include -#include // #include using namespace fun; @@ -21,58 +23,47 @@ static const auto Zero = doctest::Approx(0).epsilon(0.01); * @return true * @return false */ -template -inline auto ApproxZero(const T& a) -> bool -{ +template inline auto ApproxZero(const T& a) -> bool { return a[0] == Zero && a[1] == Zero && a[2] == Zero; } -template -void chk_ck(const PG& myck) -{ +template void chk_ck(const PG& myck) { using P = typename PG::point_t; using K = Value_type

; - auto a1 = P {1, -2, 3}; - auto a2 = P {4, 0, 6}; - auto a3 = P {-7, 1, 2}; - const auto triangle = - std::tuple {std::move(a1), std::move(a2), std::move(a3)}; + auto a1 = P{1, -2, 3}; + auto a2 = P{4, 0, 6}; + auto a3 = P{-7, 1, 2}; + const auto triangle = std::tuple{std::move(a1), std::move(a2), std::move(a3)}; const auto trilateral = tri_dual(triangle); const auto& [l1, l2, l3] = trilateral; const auto [t1, t2, t3] = myck.tri_altitude(triangle); auto o = myck.orthocenter(triangle); const auto tau = myck.reflect(l1); - const auto Q = std::tuple {myck.tri_quadrance(triangle)}; - const auto S = std::tuple {myck.tri_spread(trilateral)}; + const auto Q = std::tuple{myck.tri_quadrance(triangle)}; + const auto S = std::tuple{myck.tri_spread(trilateral)}; - const auto a4 = P {3, 0, 2}; + const auto a4 = P{3, 0, 2}; - if constexpr (Integral) - { + if constexpr (Integral) { CHECK(incident(l1, a2)); CHECK(myck.is_perpendicular(t1, l1)); CHECK(coincident(t1 * t2, t3)); CHECK(o == t2 * t3); - CHECK(a1 == - myck.orthocenter( - std::tuple {std::move(o), std::move(a2), std::move(a3)})); + CHECK(a1 == myck.orthocenter(std::tuple{std::move(o), std::move(a2), std::move(a3)})); CHECK(tau(tau(a4)) == a4); CHECK(myck.spread(l2, l2) == 0); CHECK(myck.spread(l3, l3) == 0); CHECK(myck.quadrance(a1, a1) == 0); CHECK(check_sine_law(Q, S)); CHECK(check_sine_law(S, Q)); - } - else - { + } else { CHECK(l1.dot(a2) == Zero); CHECK(l1.dot(myck.perp(t1)) == Zero); CHECK(t1.dot(t2 * t3) == Zero); CHECK(ApproxZero(cross(o, t2 * t3))); - const auto o2 = myck.orthocenter( - std::tuple {std::move(o), std::move(a2), std::move(a3)}); + const auto o2 = myck.orthocenter(std::tuple{std::move(o), std::move(a2), std::move(a3)}); CHECK(ApproxZero(cross(a1, o2))); CHECK(ApproxZero(cross(tau(tau(a4)), a4))); CHECK(myck.measure(l2, l2) == Zero); @@ -89,30 +80,23 @@ void chk_ck(const PG& myck) } template -requires Projective_plane_prim // c++20 concept -struct myck : ck -{ - [[nodiscard]] constexpr auto perp(const P& v) const -> L - { +requires Projective_plane_prim // c++20 concept +struct myck : ck { + [[nodiscard]] constexpr auto perp(const P& v) const -> L { return L(-2 * v[0], v[1], -2 * v[2]); } - [[nodiscard]] constexpr auto perp(const L& v) const -> P - { - return P(-v[0], 2 * v[1], -v[2]); - } + [[nodiscard]] constexpr auto perp(const L& v) const -> P { return P(-v[0], 2 * v[1], -v[2]); } template - [[nodiscard]] constexpr auto measure(const _P& a1, const _P& a2) const - { + [[nodiscard]] constexpr auto measure(const _P& a1, const _P& a2) const { auto x = x_ratio(a1, a2, this->perp(a2), this->perp(a1)); // using Q_t = decltype(x); return 1 - x; } }; -TEST_CASE("CK plane chk_ck (int)") -{ +TEST_CASE("CK plane chk_ck (int)") { // using boost::multiprecision::cpp_int; // namespace mp = boost::multiprecision; using boost::multiprecision::cpp_int; @@ -124,17 +108,15 @@ TEST_CASE("CK plane chk_ck (int)") chk_ck(hyck>()); chk_ck(hyck>()); - auto Ire = pg_point {0, 1, 1}; - auto Iim = pg_point {1, 0, 0}; - auto l_inf = pg_line {0, -1, 1}; + auto Ire = pg_point{0, 1, 1}; + auto Iim = pg_point{1, 0, 0}; + auto l_inf = pg_line{0, -1, 1}; - auto P = - persp_euclid_plane {std::move(Ire), std::move(Iim), std::move(l_inf)}; + auto P = persp_euclid_plane{std::move(Ire), std::move(Iim), std::move(l_inf)}; chk_ck(P); } -TEST_CASE("CK plane chk_ck (float)") -{ +TEST_CASE("CK plane chk_ck (float)") { chk_ck(myck>()); chk_ck(myck>()); chk_ck(ellck>()); @@ -142,11 +124,10 @@ TEST_CASE("CK plane chk_ck (float)") chk_ck(hyck>()); chk_ck(hyck>()); - auto Ire = pg_point {0., 1., 1.}; - auto Iim = pg_point {1., 0., 0.}; - auto l_inf = pg_line {0., -1., 1.}; + auto Ire = pg_point{0., 1., 1.}; + auto Iim = pg_point{1., 0., 0.}; + auto l_inf = pg_line{0., -1., 1.}; - auto P = - persp_euclid_plane {std::move(Ire), std::move(Iim), std::move(l_inf)}; + auto P = persp_euclid_plane{std::move(Ire), std::move(Iim), std::move(l_inf)}; chk_ck(P); } diff --git a/test/source/test_concepts.cpp b/test/source/test_concepts.cpp index 5ec1f24..1dd22b4 100644 --- a/test/source/test_concepts.cpp +++ b/test/source/test_concepts.cpp @@ -4,8 +4,7 @@ class LA; -class PA -{ +class PA { public: using dual = LA; using value_type = long; @@ -22,18 +21,11 @@ class PA friend auto operator==(PA const&, PA const&) -> bool = default; [[nodiscard]] static auto aux() -> LA; - [[nodiscard]] static auto dot(LA const& /*unused*/) -> value_type - { - return {}; - } - auto operator[](size_t /*unused*/) const -> value_type - { - return {}; - } + [[nodiscard]] static auto dot(LA const& /*unused*/) -> value_type { return {}; } + auto operator[](size_t /*unused*/) const -> value_type { return {}; } }; -class LA -{ +class LA { public: using dual = PA; using value_type = long; @@ -49,14 +41,8 @@ class LA friend void operator,(LA const&, LA const&) = delete; friend auto operator==(LA const&, LA const&) -> bool = default; [[nodiscard]] static auto aux() -> PA; - [[nodiscard]] static auto dot(PA const& /*unused*/) -> value_type - { - return {}; - } - auto operator[](size_t /*unused*/) const -> value_type - { - return {}; - } + [[nodiscard]] static auto dot(PA const& /*unused*/) -> value_type { return {}; } + auto operator[](size_t /*unused*/) const -> value_type { return {}; } }; // struct RsltP @@ -77,7 +63,6 @@ class LA // friend void operator,(RsltP, RsltP) = delete; // }; - // struct RsltL // { // operator LA() const @@ -96,40 +81,20 @@ class LA // friend void operator,(RsltL, RsltL) = delete; // }; -inline auto operator*(PA const& /*unused*/, PA const& /*unused*/) -> LA -{ - return LA {}; -} -inline auto operator*(LA const& /*unused*/, LA const& /*unused*/) -> PA -{ - return PA {}; -} -inline auto PA::aux() -> LA -{ - return LA {}; -} -inline auto LA::aux() -> PA -{ - return PA {}; -} -inline auto plucker(const int& /*unused*/, const PA& /*unused*/, - const int& /*unused*/, const PA& /*unused*/) -> PA -{ - return PA {}; -} -inline auto plucker(const int& /*unused*/, const LA& /*unused*/, - const int& /*unused*/, const LA& /*unused*/) -> LA -{ - return LA {}; -} -inline auto incident(const PA& /*unused*/, const LA& /*unused*/) -> bool -{ - return true; +inline auto operator*(PA const& /*unused*/, PA const& /*unused*/) -> LA { return LA{}; } +inline auto operator*(LA const& /*unused*/, LA const& /*unused*/) -> PA { return PA{}; } +inline auto PA::aux() -> LA { return LA{}; } +inline auto LA::aux() -> PA { return PA{}; } +inline auto plucker(const int& /*unused*/, const PA& /*unused*/, const int& /*unused*/, + const PA& /*unused*/) -> PA { + return PA{}; } -inline auto incident(const LA& /*unused*/, const PA& /*unused*/) -> bool -{ - return true; +inline auto plucker(const int& /*unused*/, const LA& /*unused*/, const int& /*unused*/, + const LA& /*unused*/) -> LA { + return LA{}; } +inline auto incident(const PA& /*unused*/, const LA& /*unused*/) -> bool { return true; } +inline auto incident(const LA& /*unused*/, const PA& /*unused*/) -> bool { return true; } using namespace fun; using PArchetype = PA; @@ -137,8 +102,7 @@ using LArchetype = LA; static_assert(Projective_plane_coord); static_assert(Projective_plane_coord); -inline void test_concept_usage(PArchetype p, LArchetype l) -{ +inline void test_concept_usage(PArchetype p, LArchetype l) { coincident(p * p, p); coincident(l * l, l); harm_conj(p, p, p); diff --git a/test/source/test_ell_plane.cpp b/test/source/test_ell_plane.cpp index fb13dab..b846f35 100644 --- a/test/source/test_ell_plane.cpp +++ b/test/source/test_ell_plane.cpp @@ -1,11 +1,13 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ +#include + +#include + #include "projgeom/ck_plane.hpp" #include "projgeom/pg_line.hpp" #include "projgeom/pg_point.hpp" -#include -#include // #include using namespace fun; @@ -19,9 +21,7 @@ static const auto Zero = doctest::Approx(0).epsilon(0.01); * @return true * @return false */ -template -inline auto ApproxZero(const T& a) -> bool -{ +template inline auto ApproxZero(const T& a) -> bool { return a[0] == Zero && a[1] == Zero && a[2] == Zero; } @@ -31,34 +31,29 @@ inline auto ApproxZero(const T& a) -> bool * @tparam PG * @param[in] myck */ -template -void chk_tri(const PG& myck) -{ +template void chk_tri(const PG& myck) { using Point = typename PG::point_t; using K = Value_type; - auto a1 = Point {1, 3, 1}; - auto a2 = Point {4, 2, 1}; - auto a3 = Point {1, 1, -1}; + auto a1 = Point{1, 3, 1}; + auto a2 = Point{4, 2, 1}; + auto a3 = Point{1, 1, -1}; // auto zero = std::array {0, 0, 0}; - const auto triangle = - std::tuple {std::move(a1), std::move(a2), std::move(a3)}; + const auto triangle = std::tuple{std::move(a1), std::move(a2), std::move(a3)}; const auto trilateral = tri_dual(triangle); const auto& [l1, l2, l3] = trilateral; - const auto Q = std::tuple {myck.tri_quadrance(triangle)}; - const auto S = std::tuple {myck.tri_spread(trilateral)}; + const auto Q = std::tuple{myck.tri_quadrance(triangle)}; + const auto S = std::tuple{myck.tri_spread(trilateral)}; auto a4 = plucker(2, a1, 3, a2); - const auto collin = - std::tuple {std::move(a1), std::move(a2), std::move(a4)}; + const auto collin = std::tuple{std::move(a1), std::move(a2), std::move(a4)}; const auto Q2 = myck.tri_quadrance(collin); - if constexpr (Integral) - { + if constexpr (Integral) { CHECK(myck.perp(myck.perp(a1)) == a1); CHECK(myck.perp(myck.perp(l1)) == l1); CHECK(myck.perp(myck.perp(l2)) == l2); @@ -66,9 +61,7 @@ void chk_tri(const PG& myck) CHECK(check_cross_law(S, std::get<2>(Q)) == 0); CHECK(check_cross_law(Q, std::get<2>(S)) == 0); CHECK(check_cross_TQF(Q2) == 0); - } - else - { + } else { CHECK(ApproxZero(cross(myck.perp(myck.perp(a1)), a1))); CHECK(ApproxZero(cross(myck.perp(myck.perp(l1)), l1))); CHECK(ApproxZero(cross(myck.perp(myck.perp(l2)), l2))); @@ -79,8 +72,7 @@ void chk_tri(const PG& myck) } } -TEST_CASE("Elliptic/Hyperbolic plane") -{ +TEST_CASE("Elliptic/Hyperbolic plane") { using boost::multiprecision::cpp_int; chk_tri(ellck>()); @@ -89,8 +81,7 @@ TEST_CASE("Elliptic/Hyperbolic plane") chk_tri(hyck>()); } -TEST_CASE("Elliptic/Hyperbolic plane (double)") -{ +TEST_CASE("Elliptic/Hyperbolic plane (double)") { chk_tri(ellck>()); chk_tri(ellck>()); chk_tri(hyck>()); diff --git a/test/source/test_euclid.cpp b/test/source/test_euclid.cpp index a7a67a0..cfb12fd 100644 --- a/test/source/test_euclid.cpp +++ b/test/source/test_euclid.cpp @@ -1,13 +1,15 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ +#include + +#include + #include "projgeom/ck_plane.hpp" #include "projgeom/euclid_plane.hpp" #include "projgeom/euclid_plane_measure.hpp" #include "projgeom/pg_line.hpp" #include "projgeom/pg_point.hpp" -#include -#include // #include using namespace fun; @@ -21,9 +23,7 @@ static const auto Zero = doctest::Approx(0).epsilon(0.01); * @return true * @return false */ -template -inline auto ApproxZero(const T& a) -> bool -{ +template inline auto ApproxZero(const T& a) -> bool { return a[0] == Zero && a[1] == Zero && a[2] == Zero; } @@ -33,9 +33,7 @@ inline auto ApproxZero(const T& a) -> bool * @tparam T * @param[in] triangle */ -template -void chk_euclid(const Triple

& triangle) -{ +template void chk_euclid(const Triple

& triangle) { auto trilateral = tri_dual(triangle); const auto& [a1, a2, a3] = triangle; @@ -67,18 +65,16 @@ void chk_euclid(const Triple

& triangle) const auto& [s1, s2, s3] = S; auto tqf = sq(q1 + q2 + q3) - 2 * (q1 * q1 + q2 * q2 + q3 * q3); - auto tsf = - sq(s1 + s2 + s3) - 2 * (s1 * s1 + s2 * s2 + s3 * s3) - 4 * s1 * s2 * s3; + auto tsf = sq(s1 + s2 + s3) - 2 * (s1 * s1 + s2 * s2 + s3 * s3) - 4 * s1 * s2 * s3; auto c3 = sq(q1 + q2 - q3) / (4 * q1 * q2); auto a3p = plucker(3, a1, 4, a2); auto q1p = quadrance(a2, a3p); auto q2p = quadrance(a1, a3p); auto q3p = quadrance(a1, a2); - auto tqf2 = Ar(q1p, q2p, q3p); // get 0 + auto tqf2 = Ar(q1p, q2p, q3p); // get 0 - if constexpr (Integral) - { + if constexpr (Integral) { CHECK(!is_parallel(l1, l2)); CHECK(!is_parallel(l2, l3)); CHECK(is_perpendicular(t1, l1)); @@ -102,9 +98,7 @@ void chk_euclid(const Triple

& triangle) // std::tuple {std::move(o), std::move(a2), // std::move(a3)}); // CHECK(a1 == o2); - } - else - { + } else { CHECK(cross2(l1, l2) != Zero); CHECK(cross2(l2, l3) != Zero); CHECK(dot1(t1, l1) == Zero); @@ -129,9 +123,7 @@ void chk_euclid(const Triple

& triangle) } } -template -void chk_cyclic(const T& quadangle) -{ +template void chk_cyclic(const T& quadangle) { auto& [u1, u2, u3, u4] = quadangle; auto q12 = quadrance(u1, u2); @@ -144,43 +136,37 @@ void chk_cyclic(const T& quadangle) using P = decltype(u1); using K = Value_type

; - if constexpr (Integral) - { - auto okay = Ptolemy(std::tuple {std::move(q12), std::move(q23), - std::move(q34), std::move(q14), std::move(q24), std::move(q13)}); + if constexpr (Integral) { + auto okay = Ptolemy(std::tuple{std::move(q12), std::move(q23), std::move(q34), + std::move(q14), std::move(q24), std::move(q13)}); CHECK(okay); - } - else - { + } else { auto t = Ar(q12 * q34, q23 * q14, q13 * q24); CHECK(t == Zero); } } -TEST_CASE("Euclid plane (cpp_int)") -{ +TEST_CASE("Euclid plane (cpp_int)") { using boost::multiprecision::cpp_int; - auto a1 = pg_point {1, 3, 1}; - auto a2 = pg_point {4, 2, 1}; - auto a3 = pg_point {4, -3, 1}; + auto a1 = pg_point{1, 3, 1}; + auto a2 = pg_point{4, 2, 1}; + auto a3 = pg_point{4, -3, 1}; - auto triangle = std::tuple {std::move(a1), std::move(a2), std::move(a3)}; + auto triangle = std::tuple{std::move(a1), std::move(a2), std::move(a3)}; chk_euclid(triangle); } -TEST_CASE("Euclid plane (floating point)") -{ - auto a1 = pg_point {1., 3., 1.}; - auto a2 = pg_point {4., 2., 1.}; - auto a3 = pg_point {4., -3., 1.}; +TEST_CASE("Euclid plane (floating point)") { + auto a1 = pg_point{1., 3., 1.}; + auto a2 = pg_point{4., 2., 1.}; + auto a3 = pg_point{4., -3., 1.}; - auto triangle = std::tuple {std::move(a1), std::move(a2), std::move(a3)}; + auto triangle = std::tuple{std::move(a1), std::move(a2), std::move(a3)}; chk_euclid(triangle); } -TEST_CASE("Euclid Cyclic Points (cpp_int)") -{ +TEST_CASE("Euclid Cyclic Points (cpp_int)") { using boost::multiprecision::cpp_int; using P = pg_point; @@ -189,13 +175,11 @@ TEST_CASE("Euclid Cyclic Points (cpp_int)") auto u3 = uc_point

(-1, 2); auto u4 = uc_point

(0, 1); - auto quadangle = - std::tuple {std::move(u1), std::move(u2), std::move(u3), std::move(u4)}; + auto quadangle = std::tuple{std::move(u1), std::move(u2), std::move(u3), std::move(u4)}; chk_cyclic(quadangle); } -TEST_CASE("Euclid Cyclic Points (double)") -{ +TEST_CASE("Euclid Cyclic Points (double)") { using P = pg_point; auto u1 = uc_point

(1, 0); @@ -203,7 +187,6 @@ TEST_CASE("Euclid Cyclic Points (double)") auto u3 = uc_point

(-1, 2); auto u4 = uc_point

(0, 1); - auto quadangle = - std::tuple {std::move(u1), std::move(u2), std::move(u3), std::move(u4)}; + auto quadangle = std::tuple{std::move(u1), std::move(u2), std::move(u3), std::move(u4)}; chk_cyclic(quadangle); } diff --git a/test/source/test_frac.cpp b/test/source/test_frac.cpp index 5489f3e..3e36acd 100644 --- a/test/source/test_frac.cpp +++ b/test/source/test_frac.cpp @@ -1,39 +1,39 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ +#include + +#include + #include "projgeom/common_concepts.h" #include "projgeom/fractions.hpp" -#include -#include // #include using namespace fun; -TEST_CASE("undefined behavior") -{ +TEST_CASE("undefined behavior") { int a = 125; int c = 32; - [[maybe_unused]] int b = a >> c; // see if your tool can catch the problem + [[maybe_unused]] int b = a >> c; // see if your tool can catch the problem // std::cout << "125 >> 32 = " << b << "\n"; } -TEST_CASE("Fraction") -{ +TEST_CASE("Fraction") { using boost::multiprecision::cpp_int; static_assert(Integral); - const auto a = cpp_int {3}; - const auto b = cpp_int {4}; - const auto c = cpp_int {5}; - const auto d = cpp_int {6}; - const auto f = cpp_int {-30}; - const auto g = cpp_int {40}; - const auto z = cpp_int {0}; - const auto h = cpp_int {-g}; + const auto a = cpp_int{3}; + const auto b = cpp_int{4}; + const auto c = cpp_int{5}; + const auto d = cpp_int{6}; + const auto f = cpp_int{-30}; + const auto g = cpp_int{40}; + const auto z = cpp_int{0}; + const auto h = cpp_int{-g}; - const auto p = Fraction {a, b}; + const auto p = Fraction{a, b}; // std::cout << p << '\n'; - const auto q = Fraction {c, d}; + const auto q = Fraction{c, d}; CHECK(p == Fraction(30, 40)); CHECK(p + q == Fraction(19, 12)); @@ -41,12 +41,11 @@ TEST_CASE("Fraction") CHECK(p != 0); } -TEST_CASE("Fraction Special Cases") -{ - const auto p = Fraction {3, 4}; - const auto inf = Fraction {1, 0}; - const auto nan = Fraction {0, 0}; - const auto zero = Fraction {0, 1}; +TEST_CASE("Fraction Special Cases") { + const auto p = Fraction{3, 4}; + const auto inf = Fraction{1, 0}; + const auto nan = Fraction{0, 0}; + const auto zero = Fraction{0, 1}; CHECK(-inf < zero); CHECK(zero < inf); diff --git a/test/source/test_persp_plane.cpp b/test/source/test_persp_plane.cpp index f98a4c5..54e3efb 100644 --- a/test/source/test_persp_plane.cpp +++ b/test/source/test_persp_plane.cpp @@ -1,12 +1,14 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ -#include "projgeom/euclid_plane.hpp" // import Ar +#include + +#include + +#include "projgeom/euclid_plane.hpp" // import Ar #include "projgeom/persp_plane.hpp" #include "projgeom/pg_line.hpp" #include "projgeom/pg_point.hpp" -#include -#include // #include using namespace fun; @@ -19,18 +21,16 @@ static const auto Zero = doctest::Approx(0).epsilon(0.01); * @tparam PG * @param[in] myck */ -template -void chk_degenerate(const PG& myck) -{ +template void chk_degenerate(const PG& myck) { using Point = typename PG::point_t; // using Line = typename PG::line_t; using K = Value_type; - auto a1 = Point {-1, 0, 3}; - auto a2 = Point {4, -2, 1}; - auto a3 = Point {3, -1, 1}; + auto a1 = Point{-1, 0, 3}; + auto a2 = Point{4, -2, 1}; + auto a3 = Point{3, -1, 1}; - auto triangle = std::tuple {std::move(a1), std::move(a2), std::move(a3)}; + auto triangle = std::tuple{std::move(a1), std::move(a2), std::move(a3)}; const auto trilateral = tri_dual(triangle); // const auto& [a1, a2, a3] = triangle; @@ -47,26 +47,22 @@ void chk_degenerate(const PG& myck) const auto [s1, s2, s3] = myck.tri_spread(trilateral); const auto tqf = sq(q1 + q2 + q3) - 2 * (q1 * q1 + q2 * q2 + q3 * q3); - const auto tsf = - sq(s1 + s2 + s3) - 2 * (s1 * s1 + s2 * s2 + s3 * s3) - 4 * s1 * s2 * s3; + const auto tsf = sq(s1 + s2 + s3) - 2 * (s1 * s1 + s2 * s2 + s3 * s3) - 4 * s1 * s2 * s3; auto a4 = plucker(3, a1, 4, a2); - const auto tri2 = std::tuple {std::move(a1), std::move(a2), std::move(a4)}; + const auto tri2 = std::tuple{std::move(a1), std::move(a2), std::move(a4)}; const auto [qq1, qq2, qq3] = myck.tri_quadrance(tri2); - const auto tqf2 = Ar(qq1, qq2, qq3); // get 0 + const auto tqf2 = Ar(qq1, qq2, qq3); // get 0 - if constexpr (Integral) - { + if constexpr (Integral) { CHECK(!myck.is_parallel(l1, l2)); CHECK(!myck.is_parallel(l2, l3)); CHECK(coincident(t1 * t2, t3)); CHECK(tqf == Ar(q1, q2, q3)); CHECK(tsf == 0); CHECK(tqf2 == 0); - } - else - { + } else { CHECK(myck.l_infty().dot(l1 * l2) != Zero); CHECK(myck.l_infty().dot(l2 * l3) != Zero); CHECK(t1.dot(t2 * t3) == Zero); @@ -76,26 +72,22 @@ void chk_degenerate(const PG& myck) } } -TEST_CASE("Perspective Euclid plane (cpp_int)") -{ +TEST_CASE("Perspective Euclid plane (cpp_int)") { using boost::multiprecision::cpp_int; auto Ire = pg_point(0, 1, 1); auto Iim = pg_point(1, 0, 0); auto l_inf = pg_line(0, -1, 1); - const auto P = - persp_euclid_plane {std::move(Ire), std::move(Iim), std::move(l_inf)}; + const auto P = persp_euclid_plane{std::move(Ire), std::move(Iim), std::move(l_inf)}; chk_degenerate(P); } -TEST_CASE("Perspective Euclid plane (floating point)") -{ - auto Ire = pg_point {0., 1., 1.}; - auto Iim = pg_point {1., 0., 0.}; - auto l_inf = pg_line {0., -1., 1.}; +TEST_CASE("Perspective Euclid plane (floating point)") { + auto Ire = pg_point{0., 1., 1.}; + auto Iim = pg_point{1., 0., 0.}; + auto l_inf = pg_line{0., -1., 1.}; - const auto P = - persp_euclid_plane {std::move(Ire), std::move(Iim), std::move(l_inf)}; + const auto P = persp_euclid_plane{std::move(Ire), std::move(Iim), std::move(l_inf)}; chk_degenerate(P); } diff --git a/test/source/test_proj_plane.cpp b/test/source/test_proj_plane.cpp index 0b0292b..b3aac8a 100644 --- a/test/source/test_proj_plane.cpp +++ b/test/source/test_proj_plane.cpp @@ -1,21 +1,22 @@ /* * Distributed under the MIT License (See accompanying file /LICENSE ) */ +#include + +#include + #include "projgeom/pg_line.hpp" #include "projgeom/pg_point.hpp" #include "projgeom/proj_plane.hpp" -#include -#include // #include using namespace fun; -TEST_CASE("Projective Point") -{ +TEST_CASE("Projective Point") { using namespace std::literals; - auto p = pg_point {1. - 2i, 3. - 1i, 2. + 1i}; // complex number - auto q = pg_point {-2. + 1i, 1. - 3i, -1. - 1i}; + auto p = pg_point{1. - 2i, 3. - 1i, 2. + 1i}; // complex number + auto q = pg_point{-2. + 1i, 1. - 3i, -1. - 1i}; auto l = p * q; // std::cout << l << '\n'; @@ -39,12 +40,11 @@ TEST_CASE("Projective Point") // check_desargue(std::tuple{p, q, r}, std::tuple{s, t, u}); } -TEST_CASE("Projective Line") -{ +TEST_CASE("Projective Line") { using namespace std::complex_literals; - auto l = pg_line {1. - 2i, 3. - 1i, 2. + 1i}; // complex number - auto m = pg_line {-2. + 1i, 1. - 3i, -1. - 1i}; + auto l = pg_line{1. - 2i, 3. - 1i, 2. + 1i}; // complex number + auto m = pg_line{-2. + 1i, 1. - 3i, -1. - 1i}; auto A = l * m; auto lm = plucker(2. + 3i, l, 3. - 4i, m); @@ -66,18 +66,17 @@ TEST_CASE("Projective Line") // check_desargue(std::tuple{l, m, r}, std::tuple{s, t, u}); } -TEST_CASE("Projective Point (Special case)") -{ - auto p = pg_point {1, 3, 2}; - auto l = pg_line {-2, 3, 1}; +TEST_CASE("Projective Point (Special case)") { + auto p = pg_point{1, 3, 2}; + auto l = pg_line{-2, 3, 1}; // auto l_inf = pg_line{0, 0, 1}; - auto l_nan = pg_line {0, 0, 0}; - auto p_nan = pg_point {0, 0, 0}; + auto l_nan = pg_line{0, 0, 0}; + auto p_nan = pg_point{0, 0, 0}; CHECK(l_nan.is_NaN()); CHECK(l_nan == l_nan); - CHECK(l_nan == p * p); // join two equal points + CHECK(l_nan == p * p); // join two equal points CHECK(p_nan == l * l); CHECK(l_nan == p_nan * p); CHECK(p_nan == l_nan * l);