Browse Source

Breaking: More flexible quaternion interface;

To upgrade:

- Replace :angleAxis with :setAngleAxis.
- Replace :between with :setBetween.
bjorn 7 years ago
parent
commit
70bb7195a9
2 changed files with 52 additions and 16 deletions
  1. 24 6
      README.md
  2. 28 10
      maf.lua

+ 24 - 6
README.md

@@ -125,8 +125,8 @@ Applies a rotation `r` to the vector.
 ##### `maf.rotation(x, y, z, w)` or `maf.quat(x, y, z, w)`
 
 Creates a new rotation (quaternion) from x, y, z, w components.  Unless you are some sort of wizard
-that understands quaternions, it's probably easier to call `:angleAxis` or `:between` on the
-rotation to initialize it.
+that understands quaternions, it's probably easier to use `.fromAngleAxis`, `.fromDirection`, or
+`.between`.
 
 The following metamethods are defined for rotations:
 
@@ -146,17 +146,35 @@ Get the individual components of the rotation.
 
 Set the individual components of a rotation.  `x` can also be a rotation.
 
+##### `rotation.fromAngleAxis(angle, vector)` or `rotation.fromAngleAxis(angle, x, y, z)`
+
+Creates a new rotation from an angle/axis pair.  This is the same as creating a new rotation and
+calling `:setAngleAxis` on it.
+
+##### `rotation:setAngleAxis(angle, vector)` or `rotation:setAngleAxis(angle, x, y, z)`
+
+Set the rotation's values using angle/axis representation.
+
 ##### `angle, x, y, z = rotation:getAngleAxis()`
 
 Get the angle/axis representation of the rotation.
 
-##### `rotation:angleAxis(angle, vector)` or `rotation:angleAxis(angle, x, y, z)`
+##### `rotation.between(v1, v2)`
+
+Create a new rotation that represents the rotation between `v1` and `v2`.
+
+##### `rotation:setBetween(v1, v2)`
+
+Update an existing rotation to represent the rotation between `v1` and `v2`.
+
+##### `rotation.fromDirection(vector)` or `rotation.fromDirection(x, y, z)`
 
-Set the rotation using angle/axis representation.
+Create a new rotation from a direction vector.  The rotation will represent the rotation from the
+forward vector (0, 0, -1) to the direction vector.
 
-##### `rotation:between(v1, v2)`
+##### `rotation:setDirection(vector)` or `rotation:setDirection(x, y, z)`
 
-Set the rotation defined by rotating from `v1` to `v2`.
+Set a rotation's value to those of the direction vector.
 
 ##### `rotation:add(r2, [out])`
 

+ 28 - 10
maf.lua

@@ -5,6 +5,7 @@
 local ffi = type(jit) == 'table' and jit.status() and require 'ffi'
 local vec3, quat
 
+local forward
 local vtmp1
 local vtmp2
 local qtmp1
@@ -193,15 +194,11 @@ quat = {
       return q
     end,
 
-    getAngleAxis = function(q)
-      if q.w > 1 or q.w < -1 then q:normalize() end
-      local s = math.sqrt(1 - q.w * q.w)
-      s = s < .0001 and 1 or 1 / s
-      return 2 * math.acos(q.w), q.x * s, q.y * s, q.z * s
+    fromAngleAxis = function(angle, x, y, z)
+      return quat():setAngleAxis(angle, x, y, z)
     end,
 
-    -- Set rotation from angle/axis representation
-    angleAxis = function(q, angle, x, y, z)
+    setAngleAxis = function(q, angle, x, y, z)
       if vec3.isvec3(x) then x, y, z = x.x, x.y, x.z end
       local s = math.sin(angle * .5)
       local c = math.cos(angle * .5)
@@ -212,8 +209,18 @@ quat = {
       return q
     end,
 
-    -- Set rotation from one vector to another
-    between = function(q, u, v)
+    getAngleAxis = function(q)
+      if q.w > 1 or q.w < -1 then q:normalize() end
+      local s = math.sqrt(1 - q.w * q.w)
+      s = s < .0001 and 1 or 1 / s
+      return 2 * math.acos(q.w), q.x * s, q.y * s, q.z * s
+    end,
+
+    between = function(u, v)
+      return quat():setBetween(u, v)
+    end,
+
+    setBetween = function(q, u, v)
       local dot = u:dot(v)
       if dot > .99999 then
         q.x, q.y, q.z, q.w = 0, 0, 0, 1
@@ -226,7 +233,7 @@ quat = {
           vtmp1:cross(u)
         end
         vtmp1:normalize()
-        return q:angleAxis(math.pi, vtmp1)
+        return q:setAngleAxis(math.pi, vtmp1)
       end
 
       q.x, q.y, q.z = u.x, u.y, u.z
@@ -235,6 +242,16 @@ quat = {
       return q:normalize()
     end,
 
+    fromDirection = function(x, y, z)
+      return quat():setDirection(x, y, z)
+    end,
+
+    setDirection = function(q, x, y, z)
+      if vec3.isvec3(x) then x, y, z = x.x, x.y, x.z end
+      vtmp2.x, vtmp2.y, vtmp2.z = x, y, z
+      return q:setBetween(forward, vtmp2)
+    end,
+
     add = function(q, r, out)
       out = out or q
       out.x = q.x + r.x
@@ -324,6 +341,7 @@ else
   setmetatable(quat, quat)
 end
 
+forward = vec3(0, 0, -1)
 vtmp1 = vec3()
 vtmp2 = vec3()
 qtmp1 = quat()