Class: Snow::Mat3

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

Overview

A 3x3 matrix class. Often useful for representation rotations.

Constant Summary collapse

IDENTITY =
self.new.freeze
ONE =
self.new(Array.new(9, 1)).freeze
ZERO =
self.new(Array.new(9, 0)).freeze
SIZE =
INT2FIX(sizeof(mat3_t))
LENGTH =
INT2FIX(sizeof(mat3_t) / sizeof(s_float_t))

Class Method Summary collapse

Instance Method Summary collapse

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 Mat3’s components.

call-seq:

set(m1, m2, ..., m8, m9)   -> new mat3 with components
set([m1, m2, ..., m8, m9]) -> new mat3 with components
set(mat3)                  -> copy of mat3
set(mat4)                  -> new mat3 from mat4's inner 9x9 matrix
set(quat)                  -> quat as mat3
set(Vec3, Vec3, Vec3)      -> new mat3 with given row vectors


6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
# File 'ext/snow-math/snow-math.c', line 6304

static VALUE sm_mat3_init(int argc, VALUE *argv, VALUE sm_self)
{
  mat3_t *self = sm_unwrap_mat3(sm_self, NULL);
  size_t arr_index = 0;

  rb_check_frozen(sm_self);

  switch (argc) {

  case 0: {
    /* Identity (handled in _new) */
    break;
  }

  /* Copy Mat3 or provided [Numeric..] */
  case 1: {
    /* Copy Mat3 */
    if (SM_IS_A(argv[0], mat3)) {
      sm_unwrap_mat3(argv[0], *self);
      break;
    }

    /* Copy Mat4 */
    if (SM_IS_A(argv[0], mat4)) {
      mat4_to_mat3(*sm_unwrap_mat4(argv[0], NULL), *self);
      break;
    }

    /* Build from Quaternion */
    if (SM_IS_A(argv[0], quat)) {
      mat3_from_quat(*sm_unwrap_quat(argv[0], NULL), *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 + 9;
      s_float_t *mat_elem = *self;
      for (; arr_index < arr_end; ++arr_index, ++mat_elem) {
        *mat_elem = NUM2DBL(rb_ary_entry(arrdata, (long)arr_index));
      }
      break;
    }

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

  /* Mat3(Vec3, Vec3, Vec3) */
  case 3: {
    size_t arg_index;
    s_float_t *mat_elem = *self;
    for (arg_index = 0; arg_index < 3; ++arg_index, mat_elem += 3) {
      if (!SM_IS_A(argv[arg_index], vec3) && !SM_IS_A(argv[arg_index], vec4) && !SM_IS_A(argv[arg_index], quat)) {
        rb_raise(
          rb_eArgError,
          "Argument %d must be a Vec3, Vec4, or Quat when supplying three arguments to initialize/set",
          (int)(arg_index + 1));
      }

      sm_unwrap_vec3(argv[arg_index], mat_elem);
    }
    break;
  }

  /* Mat3(Numeric m00 .. m16) */
  case 9: {
    s_float_t *mat_elem = *self;
    VALUE *argv_p = argv;
    for (; argc; --argc, ++argv_p, ++mat_elem) {
      *mat_elem = (s_float_t)NUM2DBL(*argv_p);
    }
    break;
  }

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

  return sm_self;
}

Class Method Details

.angle_axis(*args) ⇒ Object

Returns a Mat3 describing a rotation around the given axis.

call-seq:

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


6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
# File 'ext/snow-math/snow-math.c', line 6430

static VALUE sm_mat3_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, mat3)) {
    rb_check_frozen(sm_out);
    mat3_t *out = sm_unwrap_mat3(sm_out, NULL);
    mat3_rotation(angle, (*axis)[0], (*axis)[1], (*axis)[2], *out);
  } else {
    mat3_t out;
    mat3_rotation(angle, (*axis)[0], (*axis)[1], (*axis)[2], out);
    sm_out = sm_wrap_mat3(out, self);
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

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

Allocates a new Mat3.

call-seq:

new()                      -> identity mat3
new(m1, m2, ..., m8, m9)   -> new mat3 with components
new([m1, m2, ..., m8, m9]) -> new mat3 with components
new(mat3)                  -> copy of mat3
new(mat4)                  -> new mat3 from mat4's inner 9x9 matrix
new(quat)                  -> quat as mat3
new(Vec3, Vec3, Vec3)      -> new mat3 with given row vectors


6284
6285
6286
6287
6288
6289
# File 'ext/snow-math/snow-math.c', line 6284

static VALUE sm_mat3_new(int argc, VALUE *argv, VALUE self)
{
  VALUE sm_mat = sm_wrap_mat3(g_mat3_identity, self);
  rb_obj_call_init(sm_mat, argc, argv);
  return sm_mat;
}

Instance Method Details

#==(sm_other) ⇒ Object

Tests this Mat3 and another Mat3 for equivalency.

call-seq:

mat3 == other_mat3 -> bool


6717
6718
6719
6720
6721
6722
6723
6724
# File 'ext/snow-math/snow-math.c', line 6717

static VALUE sm_mat3_equals(VALUE sm_self, VALUE sm_other)
{
  if (!RTEST(sm_other) || !SM_IS_A(sm_other, mat3)) {
    return Qfalse;
  }

  return mat3_equals(*sm_unwrap_mat3(sm_self, NULL), *sm_unwrap_mat3(sm_other, NULL)) ? Qtrue : Qfalse;
}

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

#adjoint(*args) ⇒ Object

Returns an ajoint matrix.

call-seq:

adjoint(output = nil) -> output or new mat3


5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
# File 'ext/snow-math/snow-math.c', line 5968

static VALUE sm_mat3_adjoint(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_adjoint (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_adjoint (*self, output);
    sm_out = sm_wrap_mat3(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to adjoint");
  }
  return sm_out;
}

#adjoint!Object

Calls #adjoint(self)

call-seq: adjoint! -> self



70
71
72
# File 'lib/snow-math/mat3.rb', line 70

def adjoint!
  adjoint self
end

#cofactor(*args) ⇒ Object

Returns a cofactor matrix.

call-seq:

cofactor(output = nil) -> output or new mat3


6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
# File 'ext/snow-math/snow-math.c', line 6038

static VALUE sm_mat3_cofactor(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_cofactor (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_cofactor (*self, output);
    sm_out = sm_wrap_mat3(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to cofactor");
  }
  return sm_out;
}

#cofactor!Object

Calls #cofactor(self)

call-seq: cofactor! -> self



79
80
81
# File 'lib/snow-math/mat3.rb', line 79

def cofactor!
  cofactor self
end

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

Returns a copy of self.

call-seq:

copy(output = nil) -> output or new mat3


5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
# File 'ext/snow-math/snow-math.c', line 5863

static VALUE sm_mat3_copy(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_copy (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_copy (*self, output);
    sm_out = sm_wrap_mat3(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;
}

#determinantObject

Returns the matrix determinant.

call-seq:

determinant -> float


6211
6212
6213
6214
# File 'ext/snow-math/snow-math.c', line 6211

static VALUE sm_mat3_determinant(VALUE sm_self)
{
  return mat3_determinant(*sm_unwrap_mat3(sm_self, NULL));
}

#fetchObject Also known as: []

Gets the component of the Mat3 at the given index.

call-seq: fetch(index) -> float



5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
# File 'ext/snow-math/snow-math.c', line 5796

static VALUE sm_mat3_fetch (VALUE sm_self, VALUE sm_index)
{
  static const int max_index = sizeof(mat3_t) / sizeof(s_float_t);
  const mat3_t *self = sm_unwrap_mat3(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)]);
}

#get_column3(*args) ⇒ Object

Returns a Vec3 whose components are that of the column at the given index.

call-seq:

get_column3(index, output = nil) -> output or new vec3


6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
# File 'ext/snow-math/snow-math.c', line 6535

static VALUE sm_mat3_get_column3(int argc, VALUE *argv, VALUE sm_self)
{
  mat3_t *self;
  int index;
  VALUE sm_out;

  self = sm_unwrap_mat3(sm_self, NULL);
  index = NUM2INT(argv[0]);
  sm_out = Qnil;

  if (index < 0 || index > 2) {
    rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 2)", index);
    return Qnil;
  }

  switch (argc) {
  case 2: {
    vec3_t *out;

    sm_out = argv[1];

    if (RTEST(sm_out)) {
      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);
    } else {
      goto SM_LABEL(no_output);
    }

    out = sm_unwrap_vec3(sm_out, NULL);
    mat3_get_column3(*self, index, *out);

    break;
  }

  case 1: SM_LABEL(no_output): {
    vec3_t out;
    mat3_get_column3(*self, index, out);
    sm_out = sm_wrap_vec3(out, Qnil);
    rb_obj_call_init(sm_out, 0, 0);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid number of arguments to get_column3 - expected 1 or 2");
    break;
  }
  }

  return sm_out;
}

#get_row3(*args) ⇒ Object

Returns a Vec3 whose components are that of the row at the given index.

call-seq:

get_row3(index, output = nil) -> output or new vec3


6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
# File 'ext/snow-math/snow-math.c', line 6471

static VALUE sm_mat3_get_row3(int argc, VALUE *argv, VALUE sm_self)
{
  mat3_t *self;
  int index;
  VALUE sm_out;

  self = sm_unwrap_mat3(sm_self, NULL);
  index = NUM2INT(argv[0]);
  sm_out = Qnil;

  if (index < 0 || index > 2) {
    rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 2)", index);
    return Qnil;
  }

  switch (argc) {
  case 2: {
    vec3_t *out;

    sm_out = argv[1];

    if (RTEST(sm_out)) {
      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);
    } else {
      goto SM_LABEL(no_output);
    }

    out = sm_unwrap_vec3(sm_out, NULL);
    mat3_get_row3(*self, index, *out);

    break;
  }

  case 1: SM_LABEL(no_output): {
    vec3_t out;
    mat3_get_row3(*self, index, out);
    sm_out = sm_wrap_vec3(out, Qnil);
    rb_obj_call_init(sm_out, 0, 0);
    break;
  }

  default: {
    rb_raise(rb_eArgError, "Invalid number of arguments to get_row3 - expected 1 or 2");
    break;
  }
  }

  return sm_out;
}

#inverse(*args) ⇒ Object

Returns the matrix inverse on success, nil on failure.

call-seq:

inverse(output = nil) -> output, new mat3, or nil


6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
# File 'ext/snow-math/snow-math.c', line 6224

static VALUE sm_mat3_inverse(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out = Qnil;
  mat3_t *self;

  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);

  if (argc == 1) {
    mat3_t *output;

    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }

    if (!SM_IS_A(sm_out, mat3)) {
      rb_raise(rb_eTypeError,
        "Invalid argument to output of inverse_general: expected %s, got %s",
        rb_class2name(s_sm_mat3_klass),
        rb_obj_classname(sm_out));
      return Qnil;
    }

    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    if (!mat3_inverse(*self, *output)) {
      return Qnil;
    }

  } else if (argc == 0) {
    SM_LABEL(skip_output): {
      mat3_t output;
      if (!mat3_inverse(*self, output)) {
        return Qnil;
      }

      sm_out = sm_wrap_mat3(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



61
62
63
# File 'lib/snow-math/mat3.rb', line 61

def inverse!
  inverse self
end

#inverse_rotate_vec3(*args) ⇒ Object

Convenience function to rotate a Vec3 by an inverse matrix and return the result.

call-seq:

inv_rotate_vec3(vec3, output = nil) -> output or new vec3


6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
# File 'ext/snow-math/snow-math.c', line 6162

static VALUE sm_mat3_inv_rotate_vec3(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  mat3_t *self;
  vec3_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_mat3(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);
    mat3_inv_rotate_vec3(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    vec3_t output;
    mat3_inv_rotate_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 inverse_rotate_vec3");
  }
  return sm_out;
}

#lengthObject

Returns the length of the Mat3 in components. Result is always 9.

call-seq: length -> fixnum



5850
5851
5852
5853
# File 'ext/snow-math/snow-math.c', line 5850

static VALUE sm_mat3_length (VALUE self)
{
  return SIZET2NUM(sizeof(mat3_t) / sizeof(s_float_t));
}

#load_identityObject

Sets self to the identity matrix.

call-seq:

load_identity -> self


6669
6670
6671
6672
6673
6674
# File 'ext/snow-math/snow-math.c', line 6669

static VALUE sm_mat3_identity(VALUE sm_self)
{
  mat3_t *self = sm_unwrap_mat3(sm_self, NULL);
  mat3_identity(*self);
  return sm_self;
}

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

Multiplies self and RHS and returns the result. This is a wrapper around other multiply methods. See multiply_mat3, rotate_vec3, and #scale for more reference.

In the third form, the scalar value provided is passed for all three columns when calling scale.

call-seq:

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


105
106
107
108
109
110
111
112
# File 'lib/snow-math/mat3.rb', line 105

def multiply(rhs, out = nil)
  case rhs
  when ::Snow::Mat3 then multiply_mat3(rhs, out)
  when ::Snow::Vec3 then rotate_vec3(rhs, out)
  when Numeric      then scale(rhs, rhs, rhs, out)
  else raise TypeError, "Invalid type for RHS"
  end
end

#multiply!(rhs) ⇒ Object

Calls #multiply(rhs, self).

call-seq:

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


122
123
124
125
126
127
128
# File 'lib/snow-math/mat3.rb', line 122

def multiply!(rhs)
  multiply rhs, case rhs
    when ::Snow::Mat3, Numeric then self
    when ::Snow::Vec3 then rhs
    else raise TypeError, "Invalid type for RHS"
    end
end

#multiply_mat3(*args) ⇒ Object

Multiplies this Mat3 and another and returns the result.

call-seq:

multiply_mat3(mat3, output = nil) -> output or new mat3


6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
# File 'ext/snow-math/snow-math.c', line 6073

static VALUE sm_mat3_multiply(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  mat3_t *self;
  mat3_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  SM_RAISE_IF_NOT_TYPE(sm_rhs, mat3);
  rhs = sm_unwrap_mat3(sm_rhs, NULL);
  if (argc == 2) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_multiply(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_multiply(*self, *rhs, output);
    sm_out = sm_wrap_mat3(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_mat3");
  }
  return sm_out;
}

#multiply_mat3!(rhs) ⇒ Object

Calls #multiply_mat3(rhs, self)

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



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

def multiply_mat3!(rhs)
  multiply_mat3 rhs, self
end

#orthogonal(*args) ⇒ Object

Returns an orthogonal matrix.

call-seq:

orthogonal(output = nil) -> output or new mat3


6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
# File 'ext/snow-math/snow-math.c', line 6003

static VALUE sm_mat3_orthogonal(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_orthogonal (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_orthogonal (*self, output);
    sm_out = sm_wrap_mat3(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to orthogonal");
  }
  return sm_out;
}

#orthogonal?Boolean

call-seq:

orthogonal? -> true or false

Returns whether self is an orthogonal matrix (its columns and rows are all unit vectors). Note that this allocates a new matrix. You probably don’t want to call it often.

Returns:

  • (Boolean)


175
176
177
178
# File 'lib/snow-math/mat3.rb', line 175

def orthogonal?
  temp = self.transpose
  multiply_mat3(temp, temp) == IDENTITY
end

#pitchObject

Returns the pitch (X-axis rotation) of this matrix in degrees. This assumes the matrix is orthogonal.



143
144
145
146
147
148
149
# File 'lib/snow-math/mat3.rb', line 143

def pitch
  tx = self[6]
  tz = self[8]
  Math::atan2(
    self[7],
    Math::sqrt(tx * tx + tz * tz)) * ::Snow::RADIANS_TO_DEGREES
end

#rollObject

Returns the roll (Z-axis rotation) of this matrix in degrees. This assumes the matrix is orthogonal.



163
164
165
# File 'lib/snow-math/mat3.rb', line 163

def roll
  Math::atan2(self[1], self[4]) * ::Snow::RADIANS_TO_DEGREES
end

#rotate_vec3(*args) ⇒ Object

Rotates a Vec3 using self and returns the result.

call-seq:

rotate_vec3(vec3, output = nil) -> output or new vec3


6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
# File 'ext/snow-math/snow-math.c', line 6112

static VALUE sm_mat3_rotate_vec3(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_rhs;
  VALUE sm_out;
  mat3_t *self;
  vec3_t *rhs;
  rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out);
  self = sm_unwrap_mat3(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);
    mat3_rotate_vec3(*self, *rhs, *output);
  }} else if (argc == 1) {
SM_LABEL(skip_output): {
    vec3_t output;
    mat3_rotate_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 rotate_vec3");
  }
  return sm_out;
}

#scale(*args) ⇒ Object Also known as: **

Scales Mat3’s columns by X, Y, and Z and returns the result.

call-seq:

scale(x, y, z, output = nil) -> output or new mat3


6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
# File 'ext/snow-math/snow-math.c', line 6684

static VALUE sm_mat3_scale(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  VALUE sm_x, sm_y, sm_z;
  s_float_t x, y, z;
  mat3_t *self = sm_unwrap_mat3(sm_self, NULL);

  rb_scan_args(argc, argv, "31", &sm_x, &sm_y, &sm_z, &sm_out);
  x = NUM2DBL(sm_x);
  y = NUM2DBL(sm_y);
  z = NUM2DBL(sm_z);

  if (SM_IS_A(sm_out, mat3)) {
    rb_check_frozen(sm_out);
    mat3_scale(*self, x, y, z, *sm_unwrap_mat3(sm_out, NULL));
  } else {
    mat3_t out;
    mat3_scale(*self, x, y, z, out);
    sm_out = sm_wrap_mat3(out, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }

  return sm_out;
}

#scale!(x, y, z) ⇒ Object

Calls scale(x, y, z, self)

call-seq: scale!(x, y, z) -> self



135
136
137
# File 'lib/snow-math/mat3.rb', line 135

def scale!(x, y, z)
  scale x, y, z, self
end

#set(*args) ⇒ Object

Sets the Mat3’s components.

call-seq:

set(m1, m2, ..., m8, m9)   -> new mat3 with components
set([m1, m2, ..., m8, m9]) -> new mat3 with components
set(mat3)                  -> copy of mat3
set(mat4)                  -> new mat3 from mat4's inner 9x9 matrix
set(quat)                  -> quat as mat3
set(Vec3, Vec3, Vec3)      -> new mat3 with given row vectors


6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
# File 'ext/snow-math/snow-math.c', line 6304

static VALUE sm_mat3_init(int argc, VALUE *argv, VALUE sm_self)
{
  mat3_t *self = sm_unwrap_mat3(sm_self, NULL);
  size_t arr_index = 0;

  rb_check_frozen(sm_self);

  switch (argc) {

  case 0: {
    /* Identity (handled in _new) */
    break;
  }

  /* Copy Mat3 or provided [Numeric..] */
  case 1: {
    /* Copy Mat3 */
    if (SM_IS_A(argv[0], mat3)) {
      sm_unwrap_mat3(argv[0], *self);
      break;
    }

    /* Copy Mat4 */
    if (SM_IS_A(argv[0], mat4)) {
      mat4_to_mat3(*sm_unwrap_mat4(argv[0], NULL), *self);
      break;
    }

    /* Build from Quaternion */
    if (SM_IS_A(argv[0], quat)) {
      mat3_from_quat(*sm_unwrap_quat(argv[0], NULL), *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 + 9;
      s_float_t *mat_elem = *self;
      for (; arr_index < arr_end; ++arr_index, ++mat_elem) {
        *mat_elem = NUM2DBL(rb_ary_entry(arrdata, (long)arr_index));
      }
      break;
    }

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

  /* Mat3(Vec3, Vec3, Vec3) */
  case 3: {
    size_t arg_index;
    s_float_t *mat_elem = *self;
    for (arg_index = 0; arg_index < 3; ++arg_index, mat_elem += 3) {
      if (!SM_IS_A(argv[arg_index], vec3) && !SM_IS_A(argv[arg_index], vec4) && !SM_IS_A(argv[arg_index], quat)) {
        rb_raise(
          rb_eArgError,
          "Argument %d must be a Vec3, Vec4, or Quat when supplying three arguments to initialize/set",
          (int)(arg_index + 1));
      }

      sm_unwrap_vec3(argv[arg_index], mat_elem);
    }
    break;
  }

  /* Mat3(Numeric m00 .. m16) */
  case 9: {
    s_float_t *mat_elem = *self;
    VALUE *argv_p = argv;
    for (; argc; --argc, ++argv_p, ++mat_elem) {
      *mat_elem = (s_float_t)NUM2DBL(*argv_p);
    }
    break;
  }

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

  return sm_self;
}

#set_column3(sm_index, sm_value) ⇒ Object

Sets the matrix’s column at the given index to the given vector.

call-seq:

set_column3(index, value) -> self


6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
# File 'ext/snow-math/snow-math.c', line 6634

static VALUE sm_mat3_set_column3(VALUE sm_self, VALUE sm_index, VALUE sm_value)
{
  const vec3_t *value;
  int index;
  mat3_t *self;

  if (!SM_IS_A(sm_value, vec3) && !SM_IS_A(sm_value, vec4) && !SM_IS_A(sm_value, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_THREE_OR_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_value));
    return Qnil;
  }

  self = sm_unwrap_mat3(sm_self, NULL);
  value = sm_unwrap_vec3(sm_value, NULL);
  index = NUM2INT(sm_index);

  if (index < 0 || index > 2) {
    rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 2)", index);
    return Qnil;
  }

  mat3_set_column3(index, *value, *self);

  return sm_self;
}

#set_row3(sm_index, sm_value) ⇒ Object

Sets the matrix’s row at the given index to the given vector.

call-seq:

set_row3(index, vec3) -> self


6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
# File 'ext/snow-math/snow-math.c', line 6599

static VALUE sm_mat3_set_row3(VALUE sm_self, VALUE sm_index, VALUE sm_value)
{
  const vec3_t *value;
  int index;
  mat3_t *self;

  if (!SM_IS_A(sm_value, vec3) && !SM_IS_A(sm_value, vec4) && !SM_IS_A(sm_value, quat)) {
    rb_raise(rb_eTypeError,
      kSM_WANT_THREE_OR_FOUR_FORMAT_LIT,
      rb_obj_classname(sm_value));
    return Qnil;
  }

  self = sm_unwrap_mat3(sm_self, NULL);
  value = sm_unwrap_vec3(sm_value, NULL);
  index = NUM2INT(sm_index);

  if (index < 0 || index > 2) {
    rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 2)", index);
    return Qnil;
  }

  mat3_set_row3(index, *value, *self);

  return sm_self;
}

#sizeObject

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

call-seq: size -> fixnum



5838
5839
5840
5841
# File 'ext/snow-math/snow-math.c', line 5838

static VALUE sm_mat3_size (VALUE self)
{
  return SIZET2NUM(sizeof(mat3_t));
}

#storeObject Also known as: []=

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

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



5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
# File 'ext/snow-math/snow-math.c', line 5815

static VALUE sm_mat3_store (VALUE sm_self, VALUE sm_index, VALUE sm_value)
{
  static const int max_index = sizeof(mat3_t) / sizeof(s_float_t);
  mat3_t *self = sm_unwrap_mat3(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;
}

#to_mat4(*args) ⇒ Object

Returns a Mat4 converted from the Mat3.

call-seq:

to_mat4(output = nil) -> output or new mat4


5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
# File 'ext/snow-math/snow-math.c', line 5898

static VALUE sm_mat3_to_mat4(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat4_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat4);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat4(sm_out, NULL);
    mat3_to_mat4 (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat4_t output;
    mat3_to_mat4 (*self, output);
    sm_out = sm_wrap_mat4(output, s_sm_mat4_klass);
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to to_mat4");
  }
  return sm_out;
}

#to_quatObject



43
44
45
# File 'lib/snow-math/mat3.rb', line 43

def to_quat
  Quat.new(self)
end

#to_sObject

Returns a string representation of self.

Mat3[].to_s     # => "{ 1.0, 0.0, 0.0,\n
                #       0.0, 1.0, 0.0,\n"
                #       0.0, 0.0, 1.0 }"

call-seq:

to_s -> string


6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
# File 'ext/snow-math/snow-math.c', line 6407

static VALUE sm_mat3_to_s(VALUE self)
{
  const s_float_t *v;
  v = (const s_float_t *)*sm_unwrap_mat3(self, NULL);
  return rb_sprintf(
    "{ "
    "%f, %f, %f" ",\n  "
    "%f, %f, %f" ",\n  "
    "%f, %f, %f"
    " }",
    v[0],   v[1],   v[2],
    v[3],   v[4],   v[5],
    v[6],   v[7],   v[8] );
}

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

Transposes this matrix and returns the result.

call-seq:

transpose(output = nil) -> output or new mat3


5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
# File 'ext/snow-math/snow-math.c', line 5933

static VALUE sm_mat3_transpose(int argc, VALUE *argv, VALUE sm_self)
{
  VALUE sm_out;
  mat3_t *self;
  rb_scan_args(argc, argv, "01", &sm_out);
  self = sm_unwrap_mat3(sm_self, NULL);
  if (argc == 1) {
    if (!RTEST(sm_out)) {
      goto SM_LABEL(skip_output);
    }{
    mat3_t *output;
    SM_RAISE_IF_NOT_TYPE(sm_out, mat3);
    rb_check_frozen(sm_out);
    output = sm_unwrap_mat3(sm_out, NULL);
    mat3_transpose (*self, *output);
  }} else if (argc == 0) {
SM_LABEL(skip_output): {
    mat3_t output;
    mat3_transpose (*self, output);
    sm_out = sm_wrap_mat3(output, rb_obj_class(sm_self));
    rb_obj_call_init(sm_out, 0, 0);
  }} else {
    rb_raise(rb_eArgError, "Invalid number of arguments to transpose");
  }
  return sm_out;
}

#transpose!Object

Calls #transpose(self)

call-seq: transpose! -> self



52
53
54
# File 'lib/snow-math/mat3.rb', line 52

def transpose!
  transpose self
end

#yawObject

Returns the yaw (Y-axis rotation) of this matrix in degrees. This assumes the matrix is orthogonal.



155
156
157
# File 'lib/snow-math/mat3.rb', line 155

def yaw
  -Math::atan2(self[6], self[8]) * ::Snow::RADIANS_TO_DEGREES
end