Task
Motor
You are encouraged to solve this task according to the task description, using any language you may know.
Related tasks


C

#include <  stdlib.h>
#include <  stdint.h>
#include <  stddef.h>
#include < stdbool.h>
#include <stdalign.h>
#include <    math.h>

/* default floating point type */
typedef float flt;

typedef vec (flt,4) quat(flt);
typedef quat(flt  ) rotor;
typedef quat(flt  ) screw;
typedef vec (flt,8) motor;

#define motor_rotor(m) *(rotor*)&(m)[0]
#define motor_screw(m) *(screw*)&(m)[4]
#include <array>
#include "vec.hpp"

template<class S>
constexpr SM_INLINE std::pair<S,S> sincos(S arg) { return { std::sin(arg), std::cos(arg) }; }

template<typename T, size_t N = 3>
struct alignas(2*sizeof(vec<T,N>)) line : std::array<vec<T,N>,2>
{
  constexpr INLINE vec<T,N>& dir() { return (*this)[0]; } 
  constexpr INLINE vec<T,N>& pos() { return (*this)[1]; }
};

template<typename T>
struct quat : vec<T,4>
{
   constexpr INLINE vec<T,3>& vector() { return this->xyz(); }
   constexpr INLINE T&        scalar() { return this->w();   }
};

template<typename T>
struct alignas(2*sizeof(quat<T>)) motor : std::array<quat<T>,2>
{
  /* accessors */
  constexpr INLINE quat<T>& rotor()  { return (*this)[0]; }
  constexpr INLINE quat<T>& screw()  { return (*this)[1]; }
  constexpr INLINE quat<T>& weight() { return (*this)[0]; }
  constexpr INLINE quat<T>& bulk()   { return (*this)[1]; }
  constexpr INLINE quat<T>& v()      { return (*this)[0]; }
  constexpr INLINE quat<T>& m()      { return (*this)[1]; }
  
  constexpr INLINE motor<T>& unitize() { ((*this) *= (*this)[0].inv_mag()); }
  motor<T>(const vec<T,3>& p, const vec<T,3>& q)
  {
     (*this)[0] = { 0.0F, 0.0F, 0.0F, -1.0F };
     (*this)[1] = (p - q).dir();
  }
  motor<T>(const line<T,3>& k, const line<T,3>& l)
  {
      (*this)[0] = quat<T>(k.v() ^  l.m(), -dot(k.v(), l.v()));
      (*this)[1] = quat<T>((l.v() ^ !k.m()) -   (k.v() ^ !l.m()), -(l.v() ^ k.m()) - (k.v() ^ l.m()));
  }
  motor<T>(const plane<T,3>& g, const plane<T,3>& h)
  {
       v() = quat<T>(cross3(g,h),dot3(g,h));
       m() = quat<T>(g.w * h.dir() - h.w * g.dir(), static_cast<T>(0));
  }

};

template<typename T>
constexpr INLINE vec<T,3> cross3(motor<T> a, motor<T> b)
{
     return a.rotor().yzx() * b.rotor().zxy()
          - a.rotor().zxy() * b.rotor().yzx();
}

template<typename T>
constexpr INLINE motor<T> make_screw(T const angle, const line<T>& axis, T const disp)
{
     auto const[s c] = sincos(angle / static_cast<T>(2));
     return motor<T>{ (quat<T>)(axis.dir().pos() * (vec<T,4>){ s, s, s,  c }),
                      (quat<T>)(axis.dir().pos() * (vec<T,4>){ c, c, c, -1 } * disp / static_cast<T>(2) +            
                                axis.pos().pos() * (vec<T,4>){ s, s, s,  s })};
}
template<typename T>
constexpr INLINE motor<T> make_rotation(T const angle, const line<T>& axis)
{
     auto const[s c] = sincos(angle / static_cast<T>(2));
     return motor<T>{ (quat<T>)(axis.dir().pos() * (vec<T,4>){ s, s, s,  c }),(quat<T>)0};
}
template<typename T>
constexpr INLINE motor<T> make_translation(const vec<T,3>& offset)
{
     return motor<T>{ (quat<T>)((vec<T,3>)0).pos(), (quat<T>)(offset / static_cast<T>(2)).dir() };
}
Type Vec4Flt
    x As Single
    y As Single
    z As Single
    w As Single
End Type

Type Vec8Flt
    As Single dato(0 To 7)
End Type

Type quat_flt As Vec4Flt
Type rotor As quat_flt
Type screw As quat_flt
Type motor As Vec8Flt

#macro motor_rotor(motor_)
    Cptr(rotor Ptr, @motor_)
#endmacro

#macro motor_screw(motor_)
    Cptr(screw Ptr, Cptr(Any Ptr, @motor_) + 16)  ' 4*Single = 16 bytes
#endmacro

' Example
Dim m As motor => { _
( 1.0, 0.0, 0.0, 0.0 ), _ ' rotor
( 0.0, 1.0, 0.0, 0.0 ) }  ' screw

Print (*r).x  ' 1.0
Print (*s).x  ' 0.0 (screw x)

(*r).x = 2.0
Print m.dato(0)  ' now 2.0

Sleep

Julia has the Quaternions package which defines a Quaternion -- for example, `Quaternion q(1, 2, 3, 4)` -- as a struct with members `q.s` as the real or scalar portion and `q.v1`, `q.v2`, and `q.v3` as the i, j, and k portions. A Quaternion can be used as a Motor type as in the C++ example. The Makie.jl plotting package uses Quaternions to define 3D plot rotations, though translations in the Makie package are usually defined with a different, 3D real number vector. A Quaternion may be defined for any Number derived type, including integer, floating point, rational, and complex numeric types.

Translation of: Wren

Disclaimer: I dunno wat n.e. uv dis meanz.

with javascript_semantics
enum VECTOR, SCALAR
type quat(sequence q)
    return sequence(q[VECTOR]) and atom(q[SCALAR])
end type

enum ROTOR, SCREW
type motor(sequence m)
    return quat(m[ROTOR]) and quat(m[SCREW])
end type

function cross(motor a, b)
    atom {aX,aY,aZ} = a[ROTOR][VECTOR],
         {bX,bY,bZ} = b[ROTOR][VECTOR]
    sequence a1 = {aY,aZ,aX},
             a2 = {aZ,aX,aY},
             b1 = {bZ,bX,bY},
             b2 = {bY,bZ,bX}
    quat res = {sq_sub(sq_mul(a1,b1),sq_mul(a2,b2)),0}
    return res
end function

quat q1 = {{1,2,3},4},
     q2 = {{5,6,7},8},
     q3 = {{0,0,0},0}
motor m1 = {q1,q3},
      m2 = {q2,q3}
printf(1,"m1: %v\n",{m1})
printf(1,"m2: %v\n",{m2})
printf(1,"m1 x m2: %v\n",{cross(m1,m2)})
Output:
m1: {{{1,2,3},4},{{0,0,0},0}}
m2: {{{5,6,7},8},{{0,0,0},0}}
m1 x m2: {{-4,8,-4},0}
Translation of: C++

As there's no task description as such, I assume that the task is to create a representation of a Motor variable in one's language though as the C/C++ examples don't make any attempt to define split-complex numbers, I've stuck with real numbers for now.

As far as the 'cross3' function is concerned, I'm not sure whether vector3 or quaternion multiplication is required - I've assumed the former for now as there's no scalar (or 'screw') term involved and nothing in the C++ code to indicate that 'quat' is a true quaternion.

Pluto has a built in vector3 class so I've used that.

local vector3 = require "pluto:vector3"

class quat
    public x, y, z, w

    function __construct(v3, w)
        assert(v3 instanceof vector3, "argument #1 must be a vector3")
        assert(type(w) == "number", "argument #2 must be a number")
        self.x = v3.x
        self.y = v3.y
        self.z = v3.z
        self.w  = w
    end

    function __tostring() return $"({self.x}, {self.y}, {self.z}, {self.w})" end
end

class motor
    static function cross3(a, b)
        assert(a instanceof motor, "argument #1 must be a motor")
        assert(a instanceof motor, "argument #2 must be a motor")
        local a1 = vector3(a.rotor.y, a.rotor.z, a.rotor.x)
        local a2 = vector3(a.rotor.z, a.rotor.x, a.rotor.y)
        local b1 = vector3(b.rotor.y, b.rotor.z, b.rotor.x)
        local b2 = vector3(b.rotor.z, b.rotor.x, b.rotor.y)
        return new quat(a1 * b2 - a2 * b1, 0)
    end

    function __construct(public rotor, public screw)
        assert(rotor instanceof quat, "argument #1 must be a quat")
        assert(screw instanceof quat, "argument #2 must be a quat")
    end

    function __tostring() return $"({self.rotor}, {self.screw})" end
end

local vec1 = vector3(1, 2, 3)
local w1   = 4
local q1   = new quat(vec1, w1)
local vec2 = vector3(5, 6, 7)
local w2   = 8
local q2   = new quat(vec2, w2)
local vec3 = vector3(0, 0, 0)
local w3   = 0
local q3   = new quat(vec3, w3)
local m1   = new motor(q1, q3)
local m2   = new motor(q2, q3)
print($"m1: {m1}")
print($"m2: {m2}")
print($"m1 x m2 = {motor.cross3(m1, m2)}")
Output:
m1: ((1, 2, 3, 4), (0, 0, 0, 0))
m2: ((5, 6, 7, 8), (0, 0, 0, 0))
m1 x m2 = (-4, 8, -4, 0)
Translation of: Pluto
Library: Wren-vector
import "./vector" for Vector3

// Vector3 class only defines multiplication by a scalar.
var Vmul = Fn.new { |v1, v2|
    return Vector3.new(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z)
}

class Quat {
    construct new(v3, w) {
        if (!(v3 is Vector3)) Fiber.abort("Argument #1 must be a Vector3.")
        if (!(w is Num)) Fiber.abort("Argument #2 must be a Num.")
        _x = v3.x
        _y = v3.y
        _z = v3.z
        _w = w
    }

    x { _x }
    y { _y }
    z { _z }
    w { _w }

    toString { "(%(_x), %(_y), %(_z), %(_w))" }
}

class Motor {
    static cross3(a, b) {
        if (!(a is Motor)) Fiber.abort("Argument #1 must be a Motor.")
        if (!(b is Motor)) Fiber.abort("Argument #2 must be a Motor.")
        var a1 = Vector3.new(a.rotor.y, a.rotor.z, a.rotor.x)
        var a2 = Vector3.new(a.rotor.z, a.rotor.x, a.rotor.y)
        var b1 = Vector3.new(b.rotor.y, b.rotor.z, b.rotor.x)
        var b2 = Vector3.new(b.rotor.z, b.rotor.x, b.rotor.y)
        return Quat.new(Vmul.call(a1, b2) - Vmul.call(a2, b1), 0)
    }

    construct new(rotor, screw) {
        if (!(rotor is Quat)) Fiber.abort("Argument #1 must be a Quat.")
        if (!(screw is Quat)) Fiber.abort("Argument #2 must be a Quat.")
        _r = rotor
        _s = screw
    }

    rotor { _r }
    screw { _s }

    toString { "(%(_r), %(_s))" }
}

var vec1 = Vector3.new(1, 2, 3)
var w1   = 4
var q1   = Quat.new(vec1, w1)
var vec2 = Vector3.new(5, 6, 7)
var w2   = 8
var q2   = Quat.new(vec2, w2)
var vec3 = Vector3.new(0, 0, 0)
var w3   = 0
var q3   = Quat.new(vec3, w3)
var m1   = Motor.new(q1, q3)
var m2   = Motor.new(q2, q3)
System.print("m1: %(m1)")
System.print("m2: %(m2)")
System.print("m1 x m2 = %(Motor.cross3(m1, m2))")
Output:
m1: ((1, 2, 3, 4), (0, 0, 0, 0))
m2: ((5, 6, 7, 8), (0, 0, 0, 0))
m1 x m2 = (-4, 8, -4, 0)