Class: Snow::Quat

Inherits:
Data
  • Object
show all
Includes:
ArraySupport, BaseMarshalSupport, FiddlePointerSupport, InspectSupport, SwizzleSupport
Defined in:
lib/snow-math/quat.rb,
lib/snow-math/ptr.rb,
lib/snow-math/to_a.rb,
lib/snow-math/inspect.rb,
lib/snow-math/marshal.rb,
lib/snow-math/swizzle.rb,
ext/snow-math/snow-math.c

Overview

A simple quaternion class for representation rotations.

Constant Summary collapse

POS_X =
self.new(1, 0, 0, 1).freeze
POS_Y =
self.new(0, 1, 0, 1).freeze
POS_Z =
self.new(0, 0, 1, 1).freeze
NEG_X =
self.new(-1, 0, 0, 1).freeze
NEG_Y =
self.new(0, -1, 0, 1).freeze
NEG_Z =
self.new(0, 0, -1, 1).freeze
ONE =
self.new(1, 1, 1, 1).freeze
ZERO =
self.new(0, 0, 0, 0).freeze
IDENTITY =
self.new(0, 0, 0, 1).freeze
SIZE =
INT2FIX(sizeof(quat_t))
LENGTH =
INT2FIX(sizeof(quat_t) / sizeof(s_float_t))
@@SWIZZLE_CHARS =
/^[xyzw]{2,4}$/
@@SWIZZLE_MAPPING =
{ 2 => ::Snow::Vec2, 3 => ::Snow::Vec3, 4 => self, 'x' => 0, 'y' => 1, 'z' => 2, 'w' => 3 }

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SwizzleSupport

#__under_method_missing__, #method_missing

Methods included from BaseMarshalSupport

#_dump, included

Methods included from InspectSupport

#inspect

Methods included from ArraySupport

#each, #map, #map!, #to_a

Methods included from FiddlePointerSupport

#to_ptr

Constructor Details

#initialize(*args) ⇒ Object

Sets the Quat’s components.

call-seq:

set(x, y, z, w = 1) -> new quaternion with components [x, y, z, w]
set([x, y, z, w])   -> new quaternion with components [x, y, z, w]
set(quat)           -> copy of quat
set(vec2)           -> new quaternion with the components [vec2.xy, 0, 1]
set(vec3)           -> new quaternion with the components [vec3.xyz, 1]
set(vec4)           -> new quaternion with the components of vec4
set(mat3)           -> new quaternion from mat3
set(mat4)           -> new quaternion from mat4


3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
# File 'ext/snow-math/snow-math.c', line 3983

static VALUE sm_quat_init(int argc, VALUE *argv, VALUE sm_self)
{
  quat_t *self = sm_unwrap_quat(sm_self, NULL);
  size_t arr_index = 0;

  rb_check_frozen(sm_self);

  switch(argc) {

  /* Default value */
  case 0: { break; }

  /* Copy or by-array */
  case 1: {
    if (SM_IS_A(argv[0], quat) ||
        SM_IS_A(argv[0], vec4)) {
      sm_unwrap_quat(argv[0], *self);
      break;
    }

    if (SM_IS_A(argv[0], vec2)) {
      sm_unwrap_vec2(argv[0], *self);
      self[0][2] = s_float_lit(0.0);
      self[0][3] = s_float_lit(1.0);
      break;
    }

    if (SM_IS_A(argv[0], vec3)) {
      sm_unwrap_vec3(argv[0], *self);
      self[0][3] = s_float_lit(1.0);
      break;
    }

    if (SM_IS_A(argv[0], mat4)) {
      const mat4_t *mat = sm_unwrap_mat4(argv[0], NULL);
      quat_from_mat4(*mat, *self);
      break;
    }

    if (SM_IS_A(argv[0], mat3)) {
      const mat3_t *mat = sm_unwrap_mat3(argv[0], NULL);
      quat_from_mat3(*mat, *self);
      break;
    }

    /* Optional offset into array provided */
    if (0) {
      case 2:
      arr_index = NUM2SIZET(argv[1]);
    }

    /* Array of values */
    if (SM_RB_IS_A(argv[0], rb_cArray)) {
      VALUE arrdata = argv[0];
      const size_t arr_end = arr_index + 3;
      s_float_t *vec_elem = *self;
      for (; arr_index < arr_end; ++arr_index, ++vec_elem) {
        *vec_elem = (s_float_t)NUM2DBL(rb_ary_entry(arrdata, (long)arr_index));
      }
      break;
    }

    rb_raise(rb_eArgError, "Expected either an array of Numerics or a Quat");
    break;
  }

  /* W */
  case 4: {
    self[0][3] = (s_float_t)NUM2DBL(argv[3]);
    case 3: /* X, Y, Z */
    self[0][0] = (s_float_t)NUM2DBL(argv[0]);
    self[0][1] = (s_float_t)NUM2DBL(argv[1]);
    self[0][2] = (s_float_t)NUM2DBL(argv[2]);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid arguments to initialize/set");
    break;
  }
  } /* switch (argc) */

  return sm_self;
}

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Snow::SwizzleSupport

Class Method Details

.angle_axis(*args) ⇒ Object

Returns a quaternion describing a rotation around a given axis.

call-seq:

angle_axis(angle_degrees, axis_vec3, output = nil) -> output or new quat


4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
# File 'ext/snow-math/snow-math.c', line 4097

static VALUE sm_quat_angle_axis(int argc, VALUE *argv, VALUE self)
{
  VALUE sm_angle;
  VALUE sm_axis;
  VALUE sm_out;
  s_float_t angle;
  const vec3_t *axis;

  rb_scan_args(argc, argv, "21", &sm_angle, &sm_axis, &sm_out);
  if (!SM_IS_A(sm_axis, vec3) && !SM_IS_A(sm_axis, vec4) && !SM_IS_A(sm_axis, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_THREE_OR_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_axis));
    return Qnil;
  }

  angle = (s_float_t)NUM2DBL(sm_angle);
  axis = sm_unwrap_vec3(sm_axis, NULL);

  if (SM_IS_A(sm_out, quat) || SM_IS_A(sm_out, vec4)) {
    rb_check_frozen(sm_out);
    quat_t *out = sm_unwrap_quat(sm_out, NULL);
    quat_from_angle_axis(angle, (*axis)[0], (*axis)[1], (*axis)[2], *out);
  } else {
    quat_t out;
    quat_from_angle_axis(angle, (*axis)[0], (*axis)[1], (*axis)[2], out);
    sm_out = sm_wrap_quat(out, self);
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

.new(*args) ⇒ Object Also known as: []

Allocates a new Quat.

call-seq:

new()               -> new identity quaternion
new(x, y, z, w = 1) -> new quaternion with components [x, y, z, w]
new([x, y, z, w])   -> new quaternion with components [x, y, z, w]
new(quat)           -> copy of quat
new(vec3)           -> new quaternion with the components [vec3.xyz, 1]
new(vec4)           -> new quaternion with the components of vec4
new(mat3)           -> new quaternion from mat3
new(mat4)           -> new quaternion from mat4


3961
3962
3963
3964
3965
3966
# File 'ext/snow-math/snow-math.c', line 3961

static VALUE sm_quat_new(int argc, VALUE *argv, VALUE self)
{
  VALUE sm_quat = sm_wrap_quat(g_quat_identity, self);
  rb_obj_call_init(sm_quat, argc, argv);
  return sm_quat;
}

Instance Method Details

#==(sm_other) ⇒ Object

Tests this Vec4 or Quat and another Vec4 or Quat for equivalency.

call-seq:

quat == other_quat -> bool
vec4 == other_vec4 -> bool
quat == vec4       -> bool
vec4 == quat       -> bool


3700
3701
3702
3703
3704
3705
3706
3707
# File 'ext/snow-math/snow-math.c', line 3700

static VALUE sm_vec4_equals(VALUE sm_self, VALUE sm_other)
{
  if (!RTEST(sm_other) || (!SM_IS_A(sm_other, vec4) && !SM_IS_A(sm_other, quat))) {
    return Qfalse;
  }

  return vec4_equals(*sm_unwrap_vec4(sm_self, NULL), *sm_unwrap_vec4(sm_other, NULL)) ? Qtrue : Qfalse;
}

#add(*args) ⇒ Object Also known as: +

Adds this and another vector or quaternion’s components together and returns the result. The result type is that of the receiver.

call-seq:

add(vec4, output = nil) -> output or new vec4 or quat


3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
# File 'ext/snow-math/snow-math.c', line 3356

static VALUE sm_vec4_add(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  vec4_t *self;
  vec4_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_vec4(sm_self, NULL);
  if (!SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_rhs));
    return Qnil;
  }
  rhs = sm_unwrap_vec4(sm_rhs, NULL);
  if (argc == 2) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec4_t *output;
    if (!SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_rhs));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec4(sm_out, NULL);
    vec4_add(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    vec4_t output;
    vec4_add(*self, *rhs, output);
    sm_out = sm_wrap_vec4(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to add");
  }
  return sm_out;
}

#add!(rhs) ⇒ Object

Calls #add(rhs, self)

call-seq: add!(rhs) -> self



193
194
195
# File 'lib/snow-math/quat.rb', line 193

def add!(rhs)
  add rhs, self
end

#addressObject

Returns the memory address of the object.

call-seq: address -> fixnum



6739
6740
6741
6742
6743
6744
# File 'ext/snow-math/snow-math.c', line 6739

static VALUE sm_get_address(VALUE sm_self)
{
  void *data_ptr = NULL;
  Data_Get_Struct(sm_self, void, data_ptr);
  return ULL2NUM((unsigned long long)data_ptr);
}

#copy(*args) ⇒ Object Also known as: dup, clone

Returns a copy of self.

call-seq:

copy(output = nil) -> output or new vec4 / quat


3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
# File 'ext/snow-math/snow-math.c', line 3046

static VALUE sm_vec4_copy(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  vec4_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_vec4(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec4_t *output;
    if (!SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_out));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec4(sm_out, NULL);
    vec4_copy (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    vec4_t output;
    vec4_copy (*self, output);
    sm_out = sm_wrap_vec4(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to copy");
  }
  return sm_out;
}

#divide(*args) ⇒ Object Also known as: /

Divides this vector or quaternion’s components by a scalar value and returns the result. The return type is that of the receiver.

call-seq:

divide(scalar, output = nil) -> output or new vec4


3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
# File 'ext/snow-math/snow-math.c', line 3666

static VALUE sm_vec4_divide(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  VALUE sm_scalar;
  s_float_t scalar;
  vec4_t *self = sm_unwrap_vec4(sm_self, NULL);

  rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
  scalar = NUM2DBL(sm_scalar);

  if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
    rb_check_frozen(sm_out);
    vec4_divide(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
  } else {
    vec4_t out;
    vec4_divide(*self, scalar, out);
    sm_out = sm_wrap_vec4(out, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

#divide!(rhs) ⇒ Object

Calls #divide(rhs, self)

call-seq: divide!(rhs) -> self



214
215
216
# File 'lib/snow-math/quat.rb', line 214

def divide!(rhs)
  divide rhs, self
end

#dot_product(sm_other) ⇒ Object Also known as: **

Returns the dot product of self and another Vec4 or Quat.

call-seq:

dot_product(vec4) -> float
dot_product(quat) -> float


3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
# File 'ext/snow-math/snow-math.c', line 3457

static VALUE sm_vec4_dot_product(VALUE sm_self, VALUE sm_other)
{
  if (!SM_IS_A(sm_other, vec4) &&
      !SM_IS_A(sm_other, quat)) {
    rb_raise(rb_eArgError,
      kSM_WANT_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_other));
    return Qnil;
  }
  return DBL2NUM(
    vec4_dot_product(
      *sm_unwrap_vec4(sm_self, NULL),
      *sm_unwrap_vec4(sm_other, NULL)));
}

#fetchObject Also known as: []

Gets the component of the Quat at the given index.

call-seq: fetch(index) -> float



3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
# File 'ext/snow-math/snow-math.c', line 3748

static VALUE sm_quat_fetch (VALUE sm_self, VALUE sm_index)
{
  static const int max_index = sizeof(quat_t) / sizeof(s_float_t);
  const quat_t *self = sm_unwrap_quat(sm_self, NULL);
  int index = NUM2INT(sm_index);
  if (index < 0 || index >= max_index) {
    rb_raise(rb_eRangeError,
      "Index %d is out of bounds, must be from 0 through %d", index, max_index - 1);
  }
  return DBL2NUM(self[0][NUM2INT(sm_index)]);
}

#inverse(*args) ⇒ Object Also known as: ~

Returns the inverse of this Quat. Note that this is not the same as the inverse of, for example, a Vec4.

call-seq:

inverse(output = nil) -> output or new quat


3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
# File 'ext/snow-math/snow-math.c', line 3816

static VALUE sm_quat_inverse(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  quat_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_quat(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    quat_t *output;
    if (!SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_out));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_quat(sm_out, NULL);
    quat_inverse (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    quat_t output;
    quat_inverse (*self, output);
    sm_out = sm_wrap_quat(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to inverse");
  }
  return sm_out;
}

#inverse!Object

Calls #inverse(self)

call-seq: inverse! -> self



136
137
138
# File 'lib/snow-math/quat.rb', line 136

def inverse!
  inverse self
end

#lengthObject

Returns the length of the Quat in components. Result is always 4.

call-seq: length -> fixnum



3802
3803
3804
3805
# File 'ext/snow-math/snow-math.c', line 3802

static VALUE sm_quat_length (VALUE self)
{
  return SIZET2NUM(sizeof(quat_t) / sizeof(s_float_t));
}

#load_identityObject

Sets self to the identity quaternion.

call-seq:

load_identity -> self


4138
4139
4140
4141
4142
4143
# File 'ext/snow-math/snow-math.c', line 4138

static VALUE sm_quat_identity(VALUE sm_self)
{
  quat_t *self = sm_unwrap_quat(sm_self, NULL);
  quat_identity(*self);
  return sm_self;
}

#magnitudeObject

Returns the magnitude of self.

call-seq:

magnitude -> float


3620
3621
3622
3623
# File 'ext/snow-math/snow-math.c', line 3620

static VALUE sm_vec4_magnitude(VALUE sm_self)
{
  return DBL2NUM(vec4_length(*sm_unwrap_vec4(sm_self, NULL)));
}

#magnitude_squaredObject

Returns the squared magnitude of self.

call-seq:

magnitude_squared -> float


3607
3608
3609
3610
# File 'ext/snow-math/snow-math.c', line 3607

static VALUE sm_vec4_magnitude_squared(VALUE sm_self)
{
  return DBL2NUM(vec4_length_squared(*sm_unwrap_vec4(sm_self, NULL)));
}

#multiply(rhs, output = nil) ⇒ Object Also known as: *

Wrapper around #multiply_quat, #multiply_vec3, and #scale respectively.

call-seq:

multiply(quat, output = nil) -> output or new quat
multiply(scalar, output = nil) -> output or new quat
multiply(vec3, output = nil) -> output or new vec3


167
168
169
170
171
172
173
174
# File 'lib/snow-math/quat.rb', line 167

def multiply(rhs, output = nil)
  case rhs
  when ::Snow::Quat then multiply_quat(rhs, output)
  when ::Snow::Vec3 then multiply_vec3(rhs, output)
  when Numeric then scale(rhs, output)
  else raise TypeError, "Invalid type for RHS"
  end
end

#multiply!(rhs) ⇒ Object

Calls #multiply(rhs, self) for scaling and Quat multiplication, otherwise calls #multiply(rhs, rhs) for Vec3 multiplication.

call-seq:

multiply!(quat) -> self
multiply!(scalar) -> self
multiply!(vec3) -> vec3


183
184
185
186
187
188
# File 'lib/snow-math/quat.rb', line 183

def multiply!(rhs)
  case rhs
  when ::Snow::Vec3 then multiply(rhs, rhs)
  else multiply(rhs, self)
  end
end

#multiply_quat(*args) ⇒ Object

Concatenates this quaternion and another and returns the result.

call-seq:

multiply_quat(quat, output = nil) -> output or new quat


3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
# File 'ext/snow-math/snow-math.c', line 3856

static VALUE sm_quat_multiply(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  quat_t *self;
  quat_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_quat(sm_self, NULL);
  if (!!SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_rhs));
    return Qnil;
  }
  rhs = sm_unwrap_quat(sm_rhs, NULL);
  if (argc == 2) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    quat_t *output;
    if (!!SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_out));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_quat(sm_out, NULL);
    quat_multiply(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    quat_t output;
    quat_multiply(*self, *rhs, output);
    sm_out = sm_wrap_quat(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to multiply_quat");
  }
  return sm_out;
}

#multiply_quat!(rhs) ⇒ Object

Calls #multiply_quat(rhs, self)

call-seq: multiply_quat!(rhs) -> self



150
151
152
# File 'lib/snow-math/quat.rb', line 150

def multiply_quat!(rhs)
  multiply_quat rhs, self
end

#multiply_vec3(*args) ⇒ Object

Multiplies a quaternion and vec3, returning the rotated vec3.

call-seq:

multiply_vec3(quat, output = nil) -> output or new quat


3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
# File 'ext/snow-math/snow-math.c', line 3905

static VALUE sm_quat_multiply_vec3(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  quat_t *self;
  vec3_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_quat(sm_self, NULL);
  if (!SM_IS_A(sm_rhs, vec3) && !SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_THREE_OR_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_rhs));
    return Qnil;
  }
  rhs = sm_unwrap_vec3(sm_rhs, NULL);
  if (argc == 2) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec3_t *output;
    if (!SM_IS_A(sm_out, vec3) && !SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_THREE_OR_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_out));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec3(sm_out, NULL);
    quat_multiply_vec3(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    vec3_t output;
    quat_multiply_vec3(*self, *rhs, output);
    sm_out = sm_wrap_vec3(output, rb_obj_class(sm_rhs));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to multiply_vec3");
  }
  return sm_out;
}

#multiply_vec3!(rhs) ⇒ Object

Calls #multiply_vec3(rhs, rhs)

call-seq: multiply_vec3!(rhs) -> rhs



157
158
159
# File 'lib/snow-math/quat.rb', line 157

def multiply_vec3!(rhs)
  multiply_vec3 rhs, rhs
end

#negate(*args) ⇒ Object Also known as: -@

Negates this vector or quaternions’s components and returns the result.

call-seq:

negate(output = nil) -> output or new vec4 or quat


3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
# File 'ext/snow-math/snow-math.c', line 3167

static VALUE sm_vec4_negate(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  vec4_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_vec4(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec4_t *output;
    if (!SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_out));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec4(sm_out, NULL);
    vec4_negate (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    vec4_t output;
    vec4_negate (*self, output);
    sm_out = sm_wrap_vec4(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to negate");
  }
  return sm_out;
}

#negate!Object

Calls #negate(self)

call-seq: negate! -> self



143
144
145
# File 'lib/snow-math/quat.rb', line 143

def negate!
  negate self
end

#normalize(*args) ⇒ Object

Returns a normalized Vec4 or Quat, depending on the type of the receiver and output.

call-seq:

normalize(output = nil) -> output or new vec4 / quat


3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
# File 'ext/snow-math/snow-math.c', line 3087

static VALUE sm_vec4_normalize(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  vec4_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_vec4(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec4_t *output;
    if (!SM_IS_A(sm_out, vec4) && !SM_IS_A(sm_out, quat)) {
     rb_raise(rb_eTypeError,
       kSM_WANT_FOUR_FORMAT_LIT,
       rb_obj_classname(sm_out));
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec4(sm_out, NULL);
    vec4_normalize (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    vec4_t output;
    vec4_normalize (*self, output);
    sm_out = sm_wrap_vec4(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to normalize");
  }
  return sm_out;
}

#normalize!Object

Calls #normalize(self)

call-seq: normalize! -> self



129
130
131
# File 'lib/snow-math/quat.rb', line 129

def normalize!
  normalize self
end

#pitchObject



225
226
227
228
229
230
231
# File 'lib/snow-math/quat.rb', line 225

def pitch
  x, y, z, w = self[0], self[1], self[2], self[3]
  tx = 2.0 * (x * z - w * y)
  ty = 2.0 * (y * z + w * x)
  tz = 1.0 - 2.0 * (x * x + y * y)
  Math::atan2(ty, Math::sqrt(tx * tx - tz * tz)) * Snow::RADIANS_TO_DEGREES
end

#rollObject



240
241
242
243
244
245
# File 'lib/snow-math/quat.rb', line 240

def roll
  x, y, z, w = self[0], self[1], self[2], self[3]
  txy = 2.0 * (x * y - w * z)
  tyy = 1.0 - 2.0 * (x * x + z * z)
  Math::atan2(txy, tyy) * Snow::RADIANS_TO_DEGREES
end

#scale(*args) ⇒ Object

Scales this vector or quaternion’s components by a scalar value and returns the result. The return type is that of the receiver.

call-seq:

scale(scalar, output = nil) -> output or new vec4


3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
# File 'ext/snow-math/snow-math.c', line 3634

static VALUE sm_vec4_scale(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  VALUE sm_scalar;
  s_float_t scalar;
  vec4_t *self = sm_unwrap_vec4(sm_self, NULL);

  rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
  scalar = NUM2DBL(sm_scalar);

  if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
    rb_check_frozen(sm_out);
    vec4_scale(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
  } else {
    vec4_t out;
    vec4_scale(*self, scalar, out);
    sm_out = sm_wrap_vec4(out, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

#scale!(rhs) ⇒ Object

Calls #scale(rhs, self)

call-seq: scale!(rhs) -> self



207
208
209
# File 'lib/snow-math/quat.rb', line 207

def scale!(rhs)
  scale rhs, self
end

#set(*args) ⇒ Object

Sets the Quat’s components.

call-seq:

set(x, y, z, w = 1) -> new quaternion with components [x, y, z, w]
set([x, y, z, w])   -> new quaternion with components [x, y, z, w]
set(quat)           -> copy of quat
set(vec2)           -> new quaternion with the components [vec2.xy, 0, 1]
set(vec3)           -> new quaternion with the components [vec3.xyz, 1]
set(vec4)           -> new quaternion with the components of vec4
set(mat3)           -> new quaternion from mat3
set(mat4)           -> new quaternion from mat4


3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
# File 'ext/snow-math/snow-math.c', line 3983

static VALUE sm_quat_init(int argc, VALUE *argv, VALUE sm_self)
{
  quat_t *self = sm_unwrap_quat(sm_self, NULL);
  size_t arr_index = 0;

  rb_check_frozen(sm_self);

  switch(argc) {

  /* Default value */
  case 0: { break; }

  /* Copy or by-array */
  case 1: {
    if (SM_IS_A(argv[0], quat) ||
        SM_IS_A(argv[0], vec4)) {
      sm_unwrap_quat(argv[0], *self);
      break;
    }

    if (SM_IS_A(argv[0], vec2)) {
      sm_unwrap_vec2(argv[0], *self);
      self[0][2] = s_float_lit(0.0);
      self[0][3] = s_float_lit(1.0);
      break;
    }

    if (SM_IS_A(argv[0], vec3)) {
      sm_unwrap_vec3(argv[0], *self);
      self[0][3] = s_float_lit(1.0);
      break;
    }

    if (SM_IS_A(argv[0], mat4)) {
      const mat4_t *mat = sm_unwrap_mat4(argv[0], NULL);
      quat_from_mat4(*mat, *self);
      break;
    }

    if (SM_IS_A(argv[0], mat3)) {
      const mat3_t *mat = sm_unwrap_mat3(argv[0], NULL);
      quat_from_mat3(*mat, *self);
      break;
    }

    /* Optional offset into array provided */
    if (0) {
      case 2:
      arr_index = NUM2SIZET(argv[1]);
    }

    /* Array of values */
    if (SM_RB_IS_A(argv[0], rb_cArray)) {
      VALUE arrdata = argv[0];
      const size_t arr_end = arr_index + 3;
      s_float_t *vec_elem = *self;
      for (; arr_index < arr_end; ++arr_index, ++vec_elem) {
        *vec_elem = (s_float_t)NUM2DBL(rb_ary_entry(arrdata, (long)arr_index));
      }
      break;
    }

    rb_raise(rb_eArgError, "Expected either an array of Numerics or a Quat");
    break;
  }

  /* W */
  case 4: {
    self[0][3] = (s_float_t)NUM2DBL(argv[3]);
    case 3: /* X, Y, Z */
    self[0][0] = (s_float_t)NUM2DBL(argv[0]);
    self[0][1] = (s_float_t)NUM2DBL(argv[1]);
    self[0][2] = (s_float_t)NUM2DBL(argv[2]);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid arguments to initialize/set");
    break;
  }
  } /* switch (argc) */

  return sm_self;
}

#sizeObject

Returns the length in bytes of the Quat. When compiled to use doubles as the base type, this is always 32. Otherwise, when compiled to use floats, it’s always 16.

call-seq: size -> fixnum



3790
3791
3792
3793
# File 'ext/snow-math/snow-math.c', line 3790

static VALUE sm_quat_size (VALUE self)
{
  return SIZET2NUM(sizeof(quat_t));
}

#slerp(*args) ⇒ Object

Returns a quaternion interpolated between self and destination using spherical linear interpolation. Alpha is the interpolation value and must be clamped from 0 to 1.

call-seq:

slerp(destination, alpha, output = nil) -> output or new quat


4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
# File 'ext/snow-math/snow-math.c', line 4155

static VALUE sm_quat_slerp(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  VALUE sm_destination;
  VALUE sm_alpha;
  quat_t *destination;
  quat_t *self = sm_unwrap_vec4(sm_self, NULL);
  s_float_t alpha;

  rb_scan_args(argc, argv, "21", &sm_destination, &sm_alpha, &sm_out);
  alpha = NUM2DBL(sm_alpha);

  if (!SM_IS_A(sm_destination, vec4) && !SM_IS_A(sm_destination, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_destination));
    return Qnil;
  }

  destination = sm_unwrap_quat(sm_destination, NULL);

  if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
    rb_check_frozen(sm_out);
    quat_slerp(*self, *destination, alpha, *sm_unwrap_quat(sm_out, NULL));
  } else {
    quat_t out;
    quat_slerp(*self, *destination, alpha, out);
    sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

#slerp!(destination, alpha) ⇒ Object

Calls #slerp(destination, alpha, self)

call-seq: slerp!(destination, alpha) -> self



221
222
223
# File 'lib/snow-math/quat.rb', line 221

def slerp!(destination, alpha)
  slerp(destination, alpha, self)
end

#storeObject Also known as: []=

Sets the Quat’s component at the index to the value.

call-seq: store(index, value) -> value



3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
# File 'ext/snow-math/snow-math.c', line 3767

static VALUE sm_quat_store (VALUE sm_self, VALUE sm_index, VALUE sm_value)
{
  static const int max_index = sizeof(quat_t) / sizeof(s_float_t);
  quat_t *self = sm_unwrap_quat(sm_self, NULL);
  int index = NUM2INT(sm_index);
  rb_check_frozen(sm_self);
  if (index < 0 || index >= max_index) {
    rb_raise(rb_eRangeError,
      "Index %d is out of bounds, must be from 0 through %d", index, max_index - 1);
  }
  self[0][index] = (s_float_t)NUM2DBL(sm_value);
  return sm_value;
}

#subtract(*args) ⇒ Object Also known as: -

Subtracts another vector or quaternion’s components from this vector’s and returns the result. The return type is that of the receiver.

call-seq:

subtract(vec4, output = nil) -> output or new vec4


3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
# File 'ext/snow-math/snow-math.c', line 3406

static VALUE sm_vec4_subtract(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  vec4_t *self;
  vec4_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_vec4(sm_self, NULL);
  if (!SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_rhs));
    return Qnil;
  }
  rhs = sm_unwrap_vec4(sm_rhs, NULL);
  if (argc == 2) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    vec4_t *output;
    if (!SM_IS_A(sm_rhs, vec4) && !SM_IS_A(sm_rhs, quat)) {
      rb_raise(rb_eTypeError,
        kSM_WANT_FOUR_FORMAT_LIT,
        rb_obj_classname(sm_rhs));
      return Qnil;
    }
    rb_check_frozen(sm_out);
    output = sm_unwrap_vec4(sm_out, NULL);
    vec4_subtract(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    vec4_t output;
    vec4_subtract(*self, *rhs, output);
    sm_out = sm_wrap_vec4(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to subtract");
  }
  return sm_out;
}

#subtract!(rhs) ⇒ Object

Calls #subtract(rhs, self)

call-seq: subtract!(rhs) -> self



200
201
202
# File 'lib/snow-math/quat.rb', line 200

def subtract!(rhs)
  subtract rhs, self
end

#to_mat3Object



62
63
64
# File 'lib/snow-math/quat.rb', line 62

def to_mat3
  Mat3.new(self)
end

#to_mat4Object



66
67
68
# File 'lib/snow-math/quat.rb', line 66

def to_mat4
  Mat4.new(self)
end

#to_quatObject



58
59
60
# File 'lib/snow-math/quat.rb', line 58

def to_quat
  Quat.new(self)
end

#to_sObject

Returns a string representation of self.

Quat[].to_s     # => "{ 0.0, 0.0, 0.0, 1.0 }"

call-seq:

to_s -> string


4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
# File 'ext/snow-math/snow-math.c', line 4078

static VALUE sm_quat_to_s(VALUE self)
{
  const s_float_t *v;
  v = (const s_float_t *)*sm_unwrap_quat(self, NULL);
  return rb_sprintf(
    "{ "
    "%f, %f, %f, %f"
    " }",
    v[0], v[1], v[2], v[3]);
}

#to_vec2Object



46
47
48
# File 'lib/snow-math/quat.rb', line 46

def to_vec2
  Vec2.new(self)
end

#to_vec3Object



50
51
52
# File 'lib/snow-math/quat.rb', line 50

def to_vec3
  Vec3.new(self)
end

#to_vec4Object



54
55
56
# File 'lib/snow-math/quat.rb', line 54

def to_vec4
  Vec4.new(self)
end

#wObject

Returns the W component of the quaternion.

call-seq: w -> float



115
116
117
# File 'lib/snow-math/quat.rb', line 115

def w
  self[3]
end

#w=(value) ⇒ Object

Sets the W component of the quaternion.

call-seq: w = value -> value



122
123
124
# File 'lib/snow-math/quat.rb', line 122

def w=(value)
  self[3] = value
end

#xObject

Returns the X component of the quaternion.

call-seq: x -> float



73
74
75
# File 'lib/snow-math/quat.rb', line 73

def x
  self[0]
end

#x=(value) ⇒ Object

Sets the X component of the quaternion.

call-seq: x = value -> value



80
81
82
# File 'lib/snow-math/quat.rb', line 80

def x=(value)
  self[0] = value
end

#yObject

Returns the Y component of the quaternion.

call-seq: y -> float



87
88
89
# File 'lib/snow-math/quat.rb', line 87

def y
  self[1]
end

#y=(value) ⇒ Object

Sets the Y component of the quaternion.

call-seq: y = value -> value



94
95
96
# File 'lib/snow-math/quat.rb', line 94

def y=(value)
  self[1] = value
end

#yawObject



233
234
235
236
237
238
# File 'lib/snow-math/quat.rb', line 233

def yaw
  x, y, z, w = self[0], self[1], self[2], self[3]
  tx = 2.0 * (x * z - w * y)
  tz = 1.0 - 2.0 * (x * x + y * y)
  -Math::atan2(tx, tz) * Snow::RADIANS_TO_DEGREES
end

#zObject

Returns the Z component of the quaternion.

call-seq: z -> float



101
102
103
# File 'lib/snow-math/quat.rb', line 101

def z
  self[2]
end

#z=(value) ⇒ Object

Sets the Z component of the quaternion.

call-seq: z = value -> value



108
109
110
# File 'lib/snow-math/quat.rb', line 108

def z=(value)
  self[2] = value
end