Git Product home page Git Product logo

klein's Introduction

edit: Project has been temporarily archived as I don't have time to maintain it at the moment. Stay tuned for an updated version of the project in the future.

License: MIT DOI

Build Status Build Status Coverity Status Codacy Badge

👉👉 Project Site 👈👈

Description

Do you need to do any of the following? Quickly? Really quickly even?

  • Projecting points onto lines, lines to planes, points to planes?
  • Measuring distances and angles between points, lines, and planes?
  • Rotate or translate points, lines, and planes?
  • Perform smooth rigid body transforms? Interpolate them smoothly?
  • Construct lines from points? Planes from points? Planes from a line and a point?
  • Intersect planes to form lines? Intersect a planes and lines to form points?

If so, then Klein is the library for you!

Klein is an implementation of P(R*_{3, 0, 1}), aka 3D Projective Geometric Algebra. It is designed for applications that demand high-throughput (animation libraries, kinematic solvers, etc). In contrast to other GA libraries, Klein does not attempt to generalize the metric or dimensionality of the space. In exchange for this loss of generality, Klein implements the algebraic operations using the full weight of SSE (Streaming SIMD Extensions) for maximum throughput.

Requirements

  • Machine with a processor that supports SSE3 or later (Steam hardware survey reports 100% market penetration)
  • C++11/14/17 compliant compiler (tested with GCC 9.2.1, Clang 9.0.1, and Visual Studio 2019)
  • Optional SSE4.1 support

Usage

You have two options to use Klein in your codebase. First, you can simply copy the contents of the public folder somewhere in your include path. Alternatively, you can include this entire project in your source tree, and using cmake, add_subdirectory(Klein) and link the klein::klein interface target.

In your code, there is a single header to include via #include <klein/klein.hpp>, at which point you can create planes, points, lines, ideal lines, bivectors, motors, directions, and use their operations. Please refer to the project site for the most up-to-date documentation.

Motivation

PGA fully streamlines traditionally used quaternions, and dual-quaternions in a single algebra. Normally, the onus is on the user to perform appropriate casts and ensure signs and memory layout are accounted for. Here, all types are unified within the geometric algebra, and operations such as applying quaternion or dual-quaternions (rotor/motor) to planes, points, and lines make sense. There is a surprising amount of uniformity in the algebra, which enables efficient implementation, a simple API, and reduced code size.

Performance Considerations

It is known that a "better" way to vectorize computation in general is to arrange the data in an SoA layout to avoid unnecessary cross-lane arithmetic or unnecessary shuffling. PGA is unique in that a given PGA multivector has a natural decomposition into 4 blocks of 4 floating-point quantities. For the even sub-algebra (isomorphic to the space of dual-quaternions) also known as the motor algebra, the geometric product can be densely packed and implemented efficiently using SSE.

References

Klein is deeply indebted to several members of the GA community and their work. Beyond the works cited here, the author stands of the shoulders of giants (Felix Klein, Sophus Lie, Arthur Cayley, William Rowan Hamilton, Julius Plücker, and William Kingdon Clifford, among others).

[1] Gunn, Charles G. (2019). Course notes Geometric Algebra for Computer Graphics, SIGGRAPH 2019. arXiv link

[2] Steven De Keninck and Charles Gunn. (2019). SIGGRAPH 2019 Geometric Algebra Course. youtube link

[3] Leo Dorst, Daniel Fontijne, Stephen Mann. (2007) Geometric Algebra for Computer Science. Burlington, MA: Morgan Kaufmann Publishers Inc.

klein's People

Contributors

devjobe avatar enkimute avatar faaux avatar jeremyong avatar jpmmaia avatar veykril avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

klein's Issues

Normalizing a plane with norm = 1 changes its values

Hi, i am using your library on Windows x64 with MSVC 2022.

When normalizing a plane which already has a eucl. norm of 1, its value changes.
The following test fails if I run it with your other tests in test/test_metric.cpp:

TEST_CASE("normalized-plane-normalization")
{
    point a{-0.5, 2, -0.5};
    point b{+0.5, 2, -0.5};
    point c{+0.5, 2, +0.5};

    // p is already normalized
    plane p = a & b & c;
    CHECK_EQ(p.norm(), 1);
    CHECK_EQ(p.e0(), -2);
    CHECK_EQ(p.e1(), 0);
    CHECK_EQ(p.e2(), 1);
    CHECK_EQ(p.e3(), 0);

    p.normalize();
    // same checks as before
    CHECK_EQ(p.norm(), 1);
    CHECK_EQ(p.e0(), -2);                 // <------- error here, expansion: -4.0f, -2
    CHECK_EQ(p.e1(), 0);
    CHECK_EQ(p.e2(), 1);
    CHECK_EQ(p.e3(), 0);
}

Using the debugger i found out that the value of p after the normalize() call is kln::point{p0_=(-4, 0, 1, 0)}.
Is this intended behaviour? (I am still learning PGA)

[QUESTION] What are the orientations of the basis elements?

In your PGA library, I guess the e1, e2, e3 basis elements correspond to the YZ, ZX and XY planes (so the planes x=0, y=0, z=0). Is that correct? Is the orientation also correct, e.g. e1 has orientation Y-direction towards Z-direction, e2 Z to X, and e3 X to Y?

And I guess e0 corresponds to the "plane at infinity" (w=0). Is it possible to also assign/visualize an orientation to e0? For example, when I'm looking at e0 along any direction vector (imagining e0 are the "stars" on a "sphere at infinity") does it have a clockwise or counter-clockwise orientation?

I'm porting your code to C#, and I'm trying to add some more comments to the code, but I don't fully understand PGA yet... I'm re-reading Charles Gunns SIGGRAPH paper to get a grip on it.

Maybe I should ask these questions on the bivector.net forum or discord?

Klein 2.0 API changes inbound

I hate breaking compatibility. Especially frequently. This issue is my attempt to explain what the issue is, what I’m doing to fix it, and what assurances can be afforded about API breakages in the future.

First, the issues:

  1. On some compilers, inheritance is causing subclasses of entity to be passed on the stack instead of in registers.
  2. On some compilers, branch optimization limits are being hit causing certain loops over constexpr variables to not get optimized out at runtime.

For Klein whose primary goal is realtime PGA, both of these problems are unacceptable. As a result, the entity base class needs to go. This will have the following consequences:

  1. Implicit conversions using the entity as a medium will go away. All conversions will be explicit
  2. Because of (1), most operators will move to separate headers (one per operation) to avoid circular dependencies while maintaining type safety
  3. All the underlying implementation structure will remain the same.

As for testing, I have vetted that the changes outlined above solve all the issues mentioned and checked assembly/perf against all major compilers. All that remains is to finalize the implementation. The internal SSE code does not need to be changed as it is just the “outer shell” that has this problem. Personally, I much prefer the new API, but it is nevertheless a breaking change. As a result, Klein will get a 2.0 label despite the 1.0 being released relatively recently.

Feel free to comment with suggestions or feedback below.

Small typo in doc?

I think the following comment should be:

a \mathbf{e}_{23} + b\mathbf{e}_{31} + c\mathbf{e}_{12}

So basically

a e₂₃ + b e₃₁ + c e₁₂

Is this correct?

Problem with precision in Euler Angles.

I am working with Microsoft Visual Studio 2019 16.6.1 in Windows 10 x64 environment.

Well. There seems to be some problem in the numerical accuracy of Euler's new angle conversion feature.

For instance; When I convert, for example, roll=90º ,pitch=90º, yaw=0º to rotor, I get in rotor: roll=0º, pitch=89.972º, yaw=0º.I find a noticeable difference between 90º and 89,972º (0.028º) that can build up too quickly.

#include <klein/public/klein/klein.hpp>

#include <cmath>
#include <iostream>

const float M_PI = 3.141592653589793238462643383279502884; /* pi */

int main()
{
	float roll_1 = 90.0;
	float pitch_1 = 90.0;
	float yaw_1 = 0.0;

	std::cout << "INPUT: roll: " << roll_1 << " pitch: " << pitch_1 << " yaw: " << yaw_1 << std::endl;

	kln::euler_angles ea_1;
	ea_1.roll = roll_1 * (M_PI / 180.0f);
	ea_1.yaw = yaw_1 * (M_PI / 180.0f);
	ea_1.pitch = pitch_1 * (M_PI / 180.0f);

	kln::rotor r;
	r = kln::rotor(ea_1);
	kln::euler_angles ea_2 = r.as_euler_angles();
	
	float roll_2 = ea_2.roll * (180.0f / M_PI);
	float yaw_2 = ea_2.yaw * (180.0f / M_PI);
	float pitch_2 = ea_2.pitch * (180.0f / M_PI);

	std::cout << "OUTPUT: roll: " << roll_2 << " pitch: " << pitch_2 << " yaw: " << yaw_2 << std::endl;
	return 0;
}

I get:

INPUT: roll: 90 pitch: 90 yaw: 0
OUTPUT: roll: 0 pitch: 89.972 yaw: 0

DJuego

FetchContent error

I get an error while running the CMake configure step in a fresh copy of the repository:

Creating directories for 'simde-populate'
  Performing download step (git clone) for 'simde-populate'
  Cloning into 'simde-src'...
  fatal: reference is not a tree: df63f88a364da6be3963b4924c327b12f88d7748
  CMake Error at simde-subbuild/simde-populate-prefix/tmp/simde-populate-gitclone.cmake:40 (message):
    Failed to checkout tag: 'df63f88a364da6be3963b4924c327b12f88d7748'

Steps to reproduce:

git clone [email protected]:jeremyong/klein.git
cd klein
cmake -B build -S .

Possible fix:

Modifying CMakeLists.txt#L35 from GIT_SHALLOW ON to GIT_SHALLOW OFF solves the issue. I'm not sure if that's the correct approach though.

Plane normalization e0 value

Hi, is there a reason that e0 value should be saved rather than normalized with everything else for a plane?

Running the test from issue #23 fails with the e0 having twice the expected value.

For the "plane-normalize" test below I checked the same plane with ganja.js and used those output values. The existing and new tests pass when the _mm_blend_ps and _mm_move_ss are removed.

diff --git a/public/klein/plane.hpp b/public/klein/plane.hpp
index 57a568a..14eef60 100644
--- a/public/klein/plane.hpp
+++ b/public/klein/plane.hpp
@@ -65,11 +65,6 @@ public:
     void normalize() noexcept
     {
         __m128 inv_norm = detail::rsqrt_nr1(detail::hi_dp_bc(p0_, p0_));
-#ifdef KLEIN_SSE_4_1
-        inv_norm = _mm_blend_ps(inv_norm, _mm_set_ss(1.f), 1);
-#else
-        inv_norm = _mm_move_ss(inv_norm, _mm_set_ss(1.f));
-#endif
         p0_ = _mm_mul_ps(inv_norm, p0_);
     }
 
diff --git a/test/test_metric.cpp b/test/test_metric.cpp
index 0687a4c..3ccc0b5 100644
--- a/test/test_metric.cpp
+++ b/test/test_metric.cpp
@@ -33,6 +33,42 @@ TEST_CASE("measure-point-to-plane")
     CHECK_EQ(std::abs((p1 ^ p2).e0123()), root_two);
 }
 
+TEST_CASE("plane-normalize")
+{
+    // d*e_0 + a*e_1 + b*e_2 + c*e_3
+    plane p{1.f, 2.f, 3.f, 4.f};
+
+    p.normalize();
+
+    CHECK_EQ(p.e0(), doctest::Approx(1.069f).epsilon(0.001));
+    CHECK_EQ(p.e1(), doctest::Approx(0.267f).epsilon(0.001));
+    CHECK_EQ(p.e2(), doctest::Approx(0.534f).epsilon(0.001));
+    CHECK_EQ(p.e3(), doctest::Approx(0.801f).epsilon(0.001));
+}
+
+TEST_CASE("normalized-plane-normalization")
+{
+    point a{-0.5, 2, -0.5};
+    point b{+0.5, 2, -0.5};
+    point c{+0.5, 2, +0.5};
+
+    // p is already normalized
+    plane p = a & b & c;
+    CHECK_EQ(p.norm(), 1);
+    CHECK_EQ(p.e0(), -2);
+    CHECK_EQ(p.e1(), 0);
+    CHECK_EQ(p.e2(), 1);
+    CHECK_EQ(p.e3(), 0);
+
+    p.normalize();
+    // same checks as before
+    CHECK_EQ(p.norm(), 1);
+    CHECK_EQ(p.e0(), -2);
+    CHECK_EQ(p.e1(), 0);
+    CHECK_EQ(p.e2(), 1);
+    CHECK_EQ(p.e3(), 0);
+}
+
 TEST_CASE("measure-point-to-line")
 {
     line l{0, 1, 0, 1, 0, 0};

Log of a motor representing a translator

Testing an example of blending with Motors of PGA and I got nan as a result. Here is a sample code:

	float W[] = {0.2f,0.1f,0.3f};

	kln::motor M0(kln::translator(10.0f,1.0f,0.0f,0.0f)); 
	kln::motor M1(kln::rotor(3.1416, 1.0f, 0.0, 0.0f));
	kln::motor M2(kln::rotor(1.0472, 0.0f, 1.0f, 0.0f));

        // removing W[0]*kln::log(M0) is OK
	kln::line blendedLine = W[0]*kln::log(M0) + W[1]*kln::log(M1) + W[2]*kln::log(M2) ;

	kln::motor blended_Motor = kln::exp(blendedLine); 
        std::cout << blended_Motor(kln::point(0.0f,0.0f,0.0f)).x()<<std::endl;

It might come from the fact that the log of translator results in an ideal line whereas the log of a motor is a real line in general.

[QUESTION] No general multivector class?

I noticed that Klein doesn't have a multivector class (besides the one in the parser for testing).

Did you pick all the operators in such a way that a multivector is never an output?

If so, there must be things that cannot be done with Klein, or, maybe multi vectors are not needed for practical tasks?

Thanks again.

Tests failed in Visual Studio 2019

Well. I built the tests without any problem in environment Windows 10 x64 with Microsoft Visual Studio 2019.

By running them some are successfully passed on. For example, sym_test.exe.

image

However there are problems with klein_test.exe

image

DJuego

Question about scaling

Hi, I've recently become interested in PGA, and am considering using it in a new Python render engine. Math (especially this kind) is not my strong suit, but the advantages of PGA are compelling .... so I'm trying to wrap this up in a Python lib with an API suited for normal people :)

I'm now a bit stuck and I was hoping you could help. Render engines and 3D modeling tools usually provide 3 kinds of transforms for an object: translations, rotations, and scaling. I understand (more or less) how rotors and translators work, but I have not seen the use of scalors (if that's how you'd call them) anywhere. Is a scaling transform/motor even possible? What about anisotropic scaling?

edit: if there's a better place to ask questions like these, please let me know, and I'll move the question there instead

MSVC2019: Code in documentation does not compile...

The code is:

#include <klein/public/klein/klein.hpp>

int main()
{
	kln::plane p{ 1, 0, 0, 3 };
	kln::point P{ 2, 0, 1 };
	kln::point P_on_p{ (p | P) * p }; // Equivalent to (P|p) * p
}

You get it in Visual Studio 2019 (Windows 10 x64):

1>------ Build started: Project: prueba_klein_msvc2019, Configuration: Debug x64 ------
1>main.cpp
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(20,32): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(20): message : see reference to variable template 'const float pi_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(25,36): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(25): message : see reference to variable template 'const float pi_2_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(30,36): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(30): message : see reference to variable template 'const float pi_4_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(36,34): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(36): message : see reference to variable template 'const float tau_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(41,30): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(41): message : see reference to variable template 'const float e_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(46,38): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(46): message : see reference to variable template 'const float sqrt2_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(52,42): warning C4305: 'initializing': truncation from 'long double' to 'const float'
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\util.hpp(52): message : see reference to variable template 'const float sqrt2_2_v<float>' being compiled
1>P:\Mis-Proyectos\Personal\prueba_klein\src\main.cpp(7,33): error C2678: binary '*': no operator found which takes a left-hand operand of type 'kln::line' (or there is no acceptable conversion)
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(152,46): message : could be 'kln::ideal_line kln::operator *(kln::ideal_line,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(161,46): message : or       'kln::ideal_line kln::operator *(kln::ideal_line,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(169,46): message : or       'kln::ideal_line kln::operator *(float,kln::ideal_line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(176,46): message : or       'kln::ideal_line kln::operator *(int,kln::ideal_line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(419,42): message : or       'kln::branch kln::operator *(kln::branch,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(427,42): message : or       'kln::branch kln::operator *(kln::branch,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(433,42): message : or       'kln::branch kln::operator *(float,kln::branch) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(439,42): message : or       'kln::branch kln::operator *(int,kln::branch) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(759,40): message : or       'kln::line kln::operator *(kln::line,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(769,40): message : or       'kln::line kln::operator *(kln::line,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(775,40): message : or       'kln::line kln::operator *(float,kln::line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\line.hpp(781,40): message : or       'kln::line kln::operator *(int,kln::line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\direction.hpp(149,45): message : or       'kln::direction kln::operator *(kln::direction,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\direction.hpp(157,45): message : or       'kln::direction kln::operator *(float,kln::direction) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\direction.hpp(163,45): message : or       'kln::direction kln::operator *(kln::direction,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\direction.hpp(169,45): message : or       'kln::direction kln::operator *(int,kln::direction) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\point.hpp(193,41): message : or       'kln::point kln::operator *(kln::point,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\point.hpp(201,41): message : or       'kln::point kln::operator *(float,kln::point) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\point.hpp(207,41): message : or       'kln::point kln::operator *(kln::point,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\point.hpp(213,41): message : or       'kln::point kln::operator *(int,kln::point) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\plane.hpp(269,41): message : or       'kln::plane kln::operator *(kln::plane,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\plane.hpp(277,41): message : or       'kln::plane kln::operator *(float,kln::plane) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\plane.hpp(283,41): message : or       'kln::plane kln::operator *(kln::plane,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\plane.hpp(289,41): message : or       'kln::plane kln::operator *(int,kln::plane) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\rotor.hpp(390,41): message : or       'kln::rotor kln::operator *(kln::rotor,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\rotor.hpp(398,41): message : or       'kln::rotor kln::operator *(kln::rotor,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\rotor.hpp(404,41): message : or       'kln::rotor kln::operator *(float,kln::rotor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\rotor.hpp(410,41): message : or       'kln::rotor kln::operator *(int,kln::rotor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\translator.hpp(231,46): message : or       'kln::translator kln::operator *(kln::translator,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\translator.hpp(240,46): message : or       'kln::translator kln::operator *(kln::translator,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\translator.hpp(248,46): message : or       'kln::translator kln::operator *(float,kln::translator) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\translator.hpp(255,46): message : or       'kln::translator kln::operator *(int,kln::translator) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\motor.hpp(547,41): message : or       'kln::motor kln::operator *(kln::motor,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\motor.hpp(557,41): message : or       'kln::motor kln::operator *(kln::motor,int) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\motor.hpp(563,41): message : or       'kln::motor kln::operator *(float,kln::motor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\motor.hpp(569,41): message : or       'kln::motor kln::operator *(int,kln::motor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\dual.hpp(67,40): message : or       'kln::dual kln::operator *(kln::dual,float) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\dual.hpp(72,40): message : or       'kln::dual kln::operator *(float,kln::dual) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(81,41): message : or       'kln::motor kln::operator *(kln::plane,kln::plane) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(88,41): message : or       'kln::motor kln::operator *(kln::plane,kln::point) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(95,41): message : or       'kln::motor kln::operator *(kln::point,kln::plane) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(104,41): message : or       'kln::rotor kln::operator *(kln::branch,kln::branch) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(114,41): message : or       'kln::motor kln::operator *(kln::line,kln::line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(124,46): message : or       'kln::translator kln::operator *(kln::point,kln::point) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(133,41): message : or       'kln::rotor kln::operator *(kln::rotor,kln::rotor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(145,40): message : or       'kln::line kln::operator *(kln::dual,kln::line) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(152,40): message : or       'kln::line kln::operator *(kln::line,kln::dual) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(158,41): message : or       'kln::motor kln::operator *(kln::rotor,kln::translator) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(167,41): message : or       'kln::motor kln::operator *(kln::translator,kln::rotor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(177,46): message : or       'kln::translator kln::operator *(kln::translator,kln::translator) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(184,41): message : or       'kln::motor kln::operator *(kln::rotor,kln::motor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(193,41): message : or       'kln::motor kln::operator *(kln::motor,kln::rotor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(202,41): message : or       'kln::motor kln::operator *(kln::translator,kln::motor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(212,41): message : or       'kln::motor kln::operator *(kln::motor,kln::translator) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\inc\klein\public\klein\geometric_product.hpp(222,41): message : or       'kln::motor kln::operator *(kln::motor,kln::motor) noexcept' [found using argument-dependent lookup]
1>P:\Mis-Proyectos\Personal\prueba_klein\src\main.cpp(7,33): message : while trying to match the argument list '(kln::line, kln::plane)'
1>Done building project "prueba_klein_msvc2019.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

This code snippet can be found here.

DJuego

invalid plane::normalized function implementation

class plane final {
...
    [[nodiscard]] plane normalized() const noexcept
    {
        plane out;
        out.normalize();
        return out;
    }
...
};

is missing an assignment. Should be:

class plane final {
...
    [[nodiscard]] plane normalized() const noexcept
    {
        plane out = *this;
        out.normalize();
        return out;
    }
...
};

vcpkg integration

Hi!

I am using vcpkg to manage dependencies on a project and I was wondering if I could use vcpkg to include klein in my project.

So I wrote a port file and made some changes to klein's CMakeLists.txt so that it creates a config package when running CMake install. Packages created this way can be included in other CMake projects by using:

find_package(klein 2.3.0 REQUIRED) // Version 2.3.0 is used as an example here
target_link_libraries(app PRIVATE klein::klein) // Other available targets are klein::klein_cxx11 and klein::klein_sse42

I was wondering if you would find these changes interesting and worth adding to the project. The changes can be seen in
create-config-package.zip. I can open a pull request with the changes if you are interested.

Emscripten

I'm about to play around with compiling this to wasm. Would you be open to a pull request for the annotations if I get it working?

gpLL generated motor rotates to orthogonal axis instead of line to line

I had some questions over at ganja.js when comparing between the two library outputs: enkimute/ganja.js#172

If I understand the ordering in the gpLL comments, it looks like the e23 and e12 are swapped in the p1 part of the motor from the loading order for line and motor constructors.

In working through the axis example I created the following patch including new tests. The old tests still pass with this change.

diff --git a/public/klein/detail/x86/x86_geometric_product.hpp b/public/klein/detail/x86/x86_geometric_product.hpp
index e7de92e..6e6e891 100644
--- a/public/klein/detail/x86/x86_geometric_product.hpp
+++ b/public/klein/detail/x86/x86_geometric_product.hpp
@@ -263,9 +263,9 @@ namespace detail
                                       __m128* KLN_RESTRICT out) noexcept
     {
         // (-a1 b1 - a3 b3 - a2 b2) +
-        // (a2 b1 - a1 b2) e12 +
-        // (a1 b3 - a3 b1) e31 +
         // (a3 b2 - a2 b3) e23 +
+        // (a1 b3 - a3 b1) e31 +
+        // (a2 b1 - a1 b2) e12 +
         // (a1 c1 + a3 c3 + a2 c2 + b1 d1 + b3 d3 + b2 d2) e0123
         // (a3 c2 - a2 c3         + b2 d3 - b3 d2) e01 +
         // (a1 c3 - a3 c1         + b3 d1 - b1 d3) e02 +
@@ -280,11 +280,11 @@ namespace detail
         __m128& p1 = *out;
         __m128& p2 = *(out + 1);
 
-        p1 = _mm_mul_ps(KLN_SWIZZLE(a, 3, 1, 2, 1), KLN_SWIZZLE(b, 2, 3, 1, 1));
+        p1 = _mm_mul_ps(KLN_SWIZZLE(a, 2, 1, 3, 1), KLN_SWIZZLE(b, 1, 3, 2, 1));
         p1 = _mm_xor_ps(p1, flip);
         p1 = _mm_sub_ps(
             p1,
-            _mm_mul_ps(KLN_SWIZZLE(a, 2, 3, 1, 3), KLN_SWIZZLE(b, 3, 1, 2, 3)));
+            _mm_mul_ps(KLN_SWIZZLE(a, 1, 3, 2, 3), KLN_SWIZZLE(b, 2, 1, 3, 3)));
         __m128 a2 = _mm_unpackhi_ps(a, a);
         __m128 b2 = _mm_unpackhi_ps(b, b);
         p1        = _mm_sub_ss(p1, _mm_mul_ss(a2, b2));
diff --git a/test/test_gp.cpp b/test/test_gp.cpp
index 155edeb..f236c82 100644
--- a/test/test_gp.cpp
+++ b/test/test_gp.cpp
@@ -124,6 +124,36 @@ TEST_CASE("multivector-gp")
         l2.normalize();
         line l3 = sqrt(l1 * l2)(l2);
         CHECK_EQ(l3.approx_eq(-l1, 0.001f), true);
+
+        // motor from y-axis to x-axis
+        l1 = (origin() & point(1,0,0)); // x-axis
+        l2 = (origin() & point(0,1,0)); // y-axis
+
+        l1.normalize();
+        l2.normalize();
+
+        l3 = sqrt(l1 * l2)(l2);
+        CHECK_EQ(l3.approx_eq(-l1, 0.001f), true);
+
+        // motor from z-axis to x-axis
+        l1 = (origin() & point(1,0,0)); // x-axis
+        l2 = (origin() & point(0,0,1)); // z-axis
+
+        l1.normalize();
+        l2.normalize();
+
+        l3 = sqrt(l1 * l2)(l2);
+        CHECK_EQ(l3.approx_eq(-l1, 0.001f), true);
+
+        // motor from z-axis to y-axis
+        l1 = (origin() & point(0,1,0)); // y-axis
+        l2 = (origin() & point(0,0,1)); // z-axis
+
+        l1.normalize();
+        l2.normalize();
+
+        l3 = sqrt(l1 * l2)(l2);
+        CHECK_EQ(l3.approx_eq(-l1, 0.001f), true);
     }
 
     SUBCASE("line/line")

I'm still unclear why the line swaps direction when moving from one line to the other. I thought if the motor was supplied the same input line it would result in the same output line, including direction, that was used to create the motor?

Euler angles for Klein?

Suggestion:

It seems interesting that, if possible, Klein supports Euler's angles "natively" in both directions (Euler <=> Klein). The representation in Euler angles (yaw, pitch, row, etc) tends to be more intuitive and understandable. At least visually. And it would also improve interoperability of klein with other libraries.

DJuego

Bug in `motor::operator=(translator t)`

I believe there is a bug in this code:

    motor& KLN_VEC_CALL operator=(translator t) noexcept
    {
        p1_ = _mm_setzero_ps();
        p2_ = t.p2_;
        return *this;
    }

The rotator p1_ should be set to identity instead of zero.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.