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?
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.
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?