Class: Snow::Quat

Inherits:
Object
  • 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

@@SWIZZLE_CHARS =
/^[xyzw]{3,4}$/
@@SWIZZLE_MAPPING =
{ 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(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


2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
# File 'ext/snow-math/snow-math.c', line 2883

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;

  switch(argc) {

  // Default value
  case 0: { break; }

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

    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], 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)rb_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)rb_num2dbl(argv[3]);
    case 3: // X, Y, Z
    self[0][0] = (s_float_t)rb_num2dbl(argv[0]);
    self[0][1] = (s_float_t)rb_num2dbl(argv[1]);
    self[0][2] = (s_float_t)rb_num2dbl(argv[2]);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid arguments to Quat.initialize");
    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


2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
# File 'ext/snow-math/snow-math.c', line 2987

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)rb_num2dbl(sm_angle);
  axis = sm_unwrap_vec3(sm_axis, NULL);

  if (SM_IS_A(sm_out, quat) || SM_IS_A(sm_out, vec4)) {
    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


2862
2863
2864
2865
2866
2867
# File 'ext/snow-math/snow-math.c', line 2862

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


2608
2609
2610
2611
2612
2613
2614
2615
# File 'ext/snow-math/snow-math.c', line 2608

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


2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
# File 'ext/snow-math/snow-math.c', line 2281

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);
    }{
    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;
    }
    vec4_t *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 vec4");
  }
  return sm_out;
}

#add!(rhs) ⇒ Object

Calls #add(rhs, self)

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



159
160
161
# File 'lib/snow-math/quat.rb', line 159

def add!(rhs)
  add rhs, self
end

#addressObject

Returns the memory address of the object.

call-seq: address -> fixnum



5564
5565
5566
5567
5568
5569
# File 'ext/snow-math/snow-math.c', line 5564

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


1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
# File 'ext/snow-math/snow-math.c', line 1985

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);
    }{
    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;
    }
    vec4_t *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


2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
# File 'ext/snow-math/snow-math.c', line 2575

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 = rb_num2dbl(sm_scalar);

  if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
    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



180
181
182
# File 'lib/snow-math/quat.rb', line 180

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


2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
# File 'ext/snow-math/snow-math.c', line 2378

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 rb_float_new(
    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



2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
# File 'ext/snow-math/snow-math.c', line 2656

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 rb_float_new(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


2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
# File 'ext/snow-math/snow-math.c', line 2723

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);
    }{
    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;
    }
    quat_t *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



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

def inverse!
  inverse self
end

#lengthObject

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

call-seq: length -> fixnum



2709
2710
2711
2712
# File 'ext/snow-math/snow-math.c', line 2709

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


3027
3028
3029
3030
3031
3032
# File 'ext/snow-math/snow-math.c', line 3027

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


2530
2531
2532
2533
# File 'ext/snow-math/snow-math.c', line 2530

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

#magnitude_squaredObject

Returns the squared magnitude of self.

call-seq:

magnitude_squared -> float


2517
2518
2519
2520
# File 'ext/snow-math/snow-math.c', line 2517

static VALUE sm_vec4_magnitude_squared(VALUE sm_self)
{
  return rb_float_new(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


133
134
135
136
137
138
139
140
# File 'lib/snow-math/quat.rb', line 133

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


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

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


2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
# File 'ext/snow-math/snow-math.c', line 2761

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);
    }{
    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;
    }
    quat_t *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 quat");
  }
  return sm_out;
}

#multiply_quat!(rhs) ⇒ Object

Calls #multiply_quat(rhs, self)

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



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

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


2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
# File 'ext/snow-math/snow-math.c', line 2808

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);
    }{
    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;
    }
    vec3_t *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 quat");
  }
  return sm_out;
}

#multiply_vec3!(rhs) ⇒ Object

Calls #multiply_vec3(rhs, rhs)

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



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

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


2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
# File 'ext/snow-math/snow-math.c', line 2100

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);
    }{
    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;
    }
    vec4_t *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



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

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


2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
# File 'ext/snow-math/snow-math.c', line 2024

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);
    }{
    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));
    }
    vec4_t *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



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

def normalize!
  normalize self
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


2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
# File 'ext/snow-math/snow-math.c', line 2544

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 = rb_num2dbl(sm_scalar);

  if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
    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



173
174
175
# File 'lib/snow-math/quat.rb', line 173

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(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


2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
# File 'ext/snow-math/snow-math.c', line 2883

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;

  switch(argc) {

  // Default value
  case 0: { break; }

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

    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], 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)rb_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)rb_num2dbl(argv[3]);
    case 3: // X, Y, Z
    self[0][0] = (s_float_t)rb_num2dbl(argv[0]);
    self[0][1] = (s_float_t)rb_num2dbl(argv[1]);
    self[0][2] = (s_float_t)rb_num2dbl(argv[2]);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid arguments to Quat.initialize");
    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



2697
2698
2699
2700
# File 'ext/snow-math/snow-math.c', line 2697

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


3044
3045
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
# File 'ext/snow-math/snow-math.c', line 3044

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 = rb_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))) {
    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



187
188
189
# File 'lib/snow-math/quat.rb', line 187

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



2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
# File 'ext/snow-math/snow-math.c', line 2675

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);
  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)rb_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


2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
# File 'ext/snow-math/snow-math.c', line 2329

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);
    }{
    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;
    }
    vec4_t *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 vec4");
  }
  return sm_out;
}

#subtract!(rhs) ⇒ Object

Calls #subtract(rhs, self)

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



166
167
168
# File 'lib/snow-math/quat.rb', line 166

def subtract!(rhs)
  subtract rhs, 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


2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
# File 'ext/snow-math/snow-math.c', line 2968

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]);
}

#wObject

Returns the W component of the quaternion.

call-seq: w -> float



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

def w
  self[3]
end

#w=(value) ⇒ Object

Sets the W component of the quaternion.

call-seq: w = value -> value



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

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

#xObject

Returns the X component of the quaternion.

call-seq: x -> float



39
40
41
# File 'lib/snow-math/quat.rb', line 39

def x
  self[0]
end

#x=(value) ⇒ Object

Sets the X component of the quaternion.

call-seq: x = value -> value



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

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

#yObject

Returns the Y component of the quaternion.

call-seq: y -> float



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

def y
  self[1]
end

#y=(value) ⇒ Object

Sets the Y component of the quaternion.

call-seq: y = value -> value



60
61
62
# File 'lib/snow-math/quat.rb', line 60

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

#zObject

Returns the Z component of the quaternion.

call-seq: z -> float



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

def z
  self[2]
end

#z=(value) ⇒ Object

Sets the Z component of the quaternion.

call-seq: z = value -> value



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

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