5 * Created by Toshi Nagata on 09/01/24.
6 * Copyright 2009 Toshi Nagata. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
25 #pragma mark ====== Global Values ======
27 VALUE rb_cVector3D, rb_cTransform, rb_cIntGroup;
29 #pragma mark ====== Utility functions (Vector/Matrix) ======
36 rb_cVector = rb_const_get(rb_cObject, rb_intern("Vector"));
43 ValueFromVector(const Vector *vp)
47 mname = rb_intern("[]");
48 return rb_funcall(rb_cVector3D, mname, 3, rb_float_new(vp->x), rb_float_new(vp->y), rb_float_new(vp->z));
52 #pragma mark ====== Vector3D Class ======
55 VectorFromValue(VALUE val, Vector *vp)
58 if (rb_obj_is_kind_of(val, rb_cVector3D)) {
59 Data_Get_Struct(val, Vector, vp1);
64 mname = rb_intern("[]");
65 vp->x = NUM2DBL(rb_Float(rb_funcall(val, mname, 1, INT2FIX(0))));
66 vp->y = NUM2DBL(rb_Float(rb_funcall(val, mname, 1, INT2FIX(1))));
67 vp->z = NUM2DBL(rb_Float(rb_funcall(val, mname, 1, INT2FIX(2))));
72 s_Vector3D_Alloc(VALUE klass)
74 Vector *vp = ALLOC(Vector);
75 vp->x = vp->y = vp->z = 0.0;
76 return Data_Wrap_Struct(klass, 0, -1, vp);
80 ValueFromVector(const Vector *vp)
83 VALUE retval = s_Vector3D_Alloc(rb_cVector3D);
84 Data_Get_Struct(retval, Vector, vp1);
95 * Returns a new Vector3D object. In the first form, a zero vector
96 * is returned. In the second form, the given vector3d is duplicated.
97 * In the third form, a vector [ary[0], ary[1], ary[2]] is returned.
98 * The argument ary can be anything that responds to '[]' method.
101 s_Vector3D_Initialize(int argc, VALUE *argv, VALUE self)
105 Data_Get_Struct(self, Vector, vp);
106 rb_scan_args(argc, argv, "01", &val);
108 VectorFromValue(val, vp);
116 * Returns 3. This method is present only to be consistent with classes like
120 s_Vector3D_Size(VALUE self)
127 * self[index] -> Float
129 * Element Reference---Returns the element at the given index. If the index is
130 * less than 0 or more than 2, an exception is thrown.
133 s_Vector3D_ElementAtIndex(VALUE self, VALUE val)
137 int n = NUM2INT(val);
138 Data_Get_Struct(self, Vector, vp);
140 rb_raise(rb_eMolbyError, "index to Vector3D out of range");
141 w = (n == 0 ? vp->x : (n == 1 ? vp->y : vp->z));
142 return rb_float_new(w);
149 * Element Assignment---Set the element at _index_. If _index_ is
150 * less than 0 or more than 2, an exception is thrown.
153 s_Vector3D_SetElementAtIndex(VALUE self, VALUE idx, VALUE val)
156 Double w = NUM2DBL(rb_Float(val));
157 int n = NUM2INT(idx);
158 Data_Get_Struct(self, Vector, vp);
160 rb_raise(rb_eMolbyError, "index to Vector3D out of range");
167 return rb_float_new(w);
172 * self == val -> bool
174 * Equality---Two vector3ds are equal if their elements are all equal.
175 * Usual caution about comparison between floating point numbers should be
176 * paid. Also consider using something like <code>vector3d.length < 1e-10</code>.
179 s_Vector3D_IsEqual(VALUE self, VALUE val)
182 Data_Get_Struct(self, Vector, vp1);
183 VectorFromValue(val, &v2);
184 if (vp1->x == v2.x && vp1->y == v2.y && vp1->z == v2.z)
191 * self + val -> (new) Vector3D
193 * Add two vectors element by element. Val is converted to Vector3D.
196 s_Vector3D_Add(VALUE self, VALUE val)
200 Data_Get_Struct(self, Vector, vp1);
201 VectorFromValue(val, &v2);
202 retval = s_Vector3D_Alloc(rb_cVector3D);
206 return ValueFromVector(&v2);
211 * self - val -> (new) Vector3D
213 * Subtract two vectors element by element. Val is converted to Vector3D.
216 s_Vector3D_Subtract(VALUE self, VALUE val)
220 Data_Get_Struct(self, Vector, vp1);
221 VectorFromValue(val, &v2);
222 retval = s_Vector3D_Alloc(rb_cVector3D);
223 v2.x = vp1->x - v2.x;
224 v2.y = vp1->y - v2.y;
225 v2.z = vp1->z - v2.z;
226 return ValueFromVector(&v2);
231 * self.dot(val) -> Float
233 * Calculate the dot (inner) product of the two vectors. Val is converted to Vector3D.
235 * <b>See Also:</b> Vector3D.*
238 s_Vector3D_Dot(VALUE self, VALUE val)
241 Data_Get_Struct(self, Vector, vp1);
242 VectorFromValue(val, &v2);
243 return rb_float_new(vp1->x * v2.x + vp1->y * v2.y + vp1->z * v2.z);
248 * self * numeric -> (new) Vector3D
249 * self * val -> Float
251 * In the first form, the vector is scaled by the numeric. In the second
252 * form, the dot (inner) product of the two vectors are returned, which is equivalent to
256 s_Vector3D_Multiply(VALUE self, VALUE val)
259 Data_Get_Struct(self, Vector, vp1);
260 if (rb_obj_is_kind_of(val, rb_cNumeric)) {
261 double w = NUM2DBL(rb_Float(val));
265 return ValueFromVector(&v2);
266 } else return s_Vector3D_Dot(self, val);
271 * self / numeric -> (new) Vector3D
273 * The vector is scaled by the inverse of the given numeric.
276 s_Vector3D_Divide(VALUE self, VALUE val)
279 double w = NUM2DBL(rb_Float(val));
280 Data_Get_Struct(self, Vector, vp1);
284 return ValueFromVector(&v2);
289 * self.cross(val) -> (new) Vector3D
291 * Calculate the cross (outer) product of the two vectors. Val is converted to Vector3D.
294 s_Vector3D_Cross(VALUE self, VALUE val)
297 Data_Get_Struct(self, Vector, vp1);
298 VectorFromValue(val, &v2);
299 v3.x = vp1->y * v2.z - vp1->z * v2.y;
300 v3.y = vp1->z * v2.x - vp1->x * v2.z;
301 v3.z = vp1->x * v2.y - vp1->y * v2.x;
302 return ValueFromVector(&v3);
307 * -self -> (new) Vector3D
309 * Calculate the opposite vector.
312 s_Vector3D_UnaryMinus(VALUE self)
315 Data_Get_Struct(self, Vector, vp);
319 return ValueFromVector(&v1);
326 * Calculate the Pythagorean length of the vector.
327 * Note that this method is <em>not</em> an alias of Vector3D#size, which returns 3.
330 s_Vector3D_Length(VALUE self)
333 Data_Get_Struct(self, Vector, vp);
334 return rb_float_new(sqrt(vp->x * vp->x + vp->y * vp->y + vp->z * vp->z));
341 * Calculate the square of the Pythagorean length of the vector.
344 s_Vector3D_Length2(VALUE self)
347 Data_Get_Struct(self, Vector, vp);
348 return rb_float_new(vp->x * vp->x + vp->y * vp->y + vp->z * vp->z);
353 * normalize -> (new) Vector3D
355 * Returns a unit vector with the same direction. Raises an exception when the
356 * vector is a zero vector.
359 s_Vector3D_Normalize(VALUE self)
363 Data_Get_Struct(self, Vector, vp);
364 w = 1.0 / sqrt(vp->x * vp->x + vp->y * vp->y + vp->z * vp->z);
366 rb_raise(rb_eMolbyError, "trying to normalize a (nearly) zero vector");
370 return ValueFromVector(&v);
377 * Returns [self.x, self.y, self.z].
380 s_Vector3D_ToArray(VALUE self)
383 Data_Get_Struct(self, Vector, vp);
384 return rb_ary_new3(3, rb_float_new(vp->x), rb_float_new(vp->y), rb_float_new(vp->z));
391 * Calls block for x, y, z elements, passing that element as a parameter.
394 s_Vector3D_Each(VALUE self)
397 Data_Get_Struct(self, Vector, vp);
398 rb_yield(rb_float_new(vp->x));
399 rb_yield(rb_float_new(vp->y));
400 rb_yield(rb_float_new(vp->z));
408 * Get the x element of the vector.
411 s_Vector3D_GetX(VALUE self)
414 Data_Get_Struct(self, Vector, vp);
415 return rb_float_new(vp->x);
422 * Get the y element of the vector.
425 s_Vector3D_GetY(VALUE self)
428 Data_Get_Struct(self, Vector, vp);
429 return rb_float_new(vp->y);
436 * Get the z element of the vector.
439 s_Vector3D_GetZ(VALUE self)
442 Data_Get_Struct(self, Vector, vp);
443 return rb_float_new(vp->z);
450 * Set the x element of the vector.
453 s_Vector3D_SetX(VALUE self, VALUE val)
456 Data_Get_Struct(self, Vector, vp);
457 vp->x = NUM2DBL(rb_Float(val));
458 return rb_float_new(vp->x);
465 * Set the y element of the vector.
468 s_Vector3D_SetY(VALUE self, VALUE val)
471 Data_Get_Struct(self, Vector, vp);
472 vp->y = NUM2DBL(rb_Float(val));
473 return rb_float_new(vp->y);
480 * Set the z element of the vector.
483 s_Vector3D_SetZ(VALUE self, VALUE val)
486 Data_Get_Struct(self, Vector, vp);
487 vp->z = NUM2DBL(rb_Float(val));
488 return rb_float_new(vp->z);
493 * Vector3d[fx, fy, fz] -> (new) Vector3D
495 * Create a new vector3d object. Equivalent to Vector3D#new([fx, fy, fz]).
498 s_Vector3D_Create(VALUE klass, VALUE args)
500 VALUE val = s_Vector3D_Alloc(klass);
501 s_Vector3D_Initialize(1, &args, val);
509 * Create a readable string like "Vector3D[fx, fy, fz]".
512 s_Vector3D_Inspect(VALUE self)
514 /* self.class.name << self.to_a.inspect */
515 /* VALUE klass = CLASS_OF(self); */
516 /* VALUE val = rb_funcall(klass, rb_intern("name"), 0); */
517 VALUE val = rb_str_new2("Vector3D");
518 self = s_Vector3D_ToArray(self);
519 return rb_funcall(val, rb_intern("<<"), 1, rb_funcall(self, rb_intern("inspect"), 0));
522 #pragma mark ====== Transform Class ======
525 TransformFromValue(VALUE val, Transform *tp)
529 if (rb_obj_is_kind_of(val, rb_cTransform)) {
530 Data_Get_Struct(val, Transform, tp1);
531 memmove(tp, tp1, sizeof(Transform));
532 } else if (TYPE(val) == T_ARRAY) {
534 (1) [[a11 a21 a31] [a12 a22 a32] [a13 a23 a33] [a14 a24 a34]] or
535 (2) [a11 a21 a31 a12 a22 a32 a13 a23 a33 a14 a24 a34] */
536 int len = RARRAY_LEN(val);
537 VALUE *valp = RARRAY_PTR(val);
539 for (i = 0; i < 12; i++)
540 (*tp)[i] = NUM2DBL(rb_Float(valp[i]));
542 } else if (len == 4) {
544 for (i = 0; i < 4; i++) {
546 if (TYPE(val2) != T_ARRAY)
547 val2 = rb_funcall(val2, rb_intern("to_a"), 0);
548 if (TYPE(val2) != T_ARRAY || RARRAY_LEN(val2) != 3)
549 goto array_format_error;
550 valp2 = RARRAY_PTR(val2);
551 for (j = 0; j < 3; j++)
552 (*tp)[3 * i + j] = NUM2DBL(rb_Float(valp2[j]));
557 rb_raise(rb_eMolbyError, "wrong array format; must be an array of either (1) four 3D column vectors or (2) 12 numerics");
559 static ID index_mid = 0, row_size_mid, column_size_mid;
560 if (index_mid == 0) {
561 index_mid = rb_intern("[]");
562 row_size_mid = rb_intern("row_size");
563 column_size_mid = rb_intern("column_size");
565 if (rb_respond_to(val, row_size_mid) && rb_respond_to(val, column_size_mid)) {
566 /* Matrix-type object */
567 for (i = 0; i < 4; i++) {
568 for (j = 0; j < 3; j++)
569 (*tp)[i * 3 + j] = NUM2DBL(rb_Float(rb_funcall(val, index_mid, 2, INT2FIX(i), INT2FIX(j))));
572 /* Other "array-like" object */
573 for (i = 0; i < 12; i++)
574 (*tp)[i] = NUM2DBL(rb_Float(rb_funcall(val, index_mid, 1, INT2FIX(i))));
580 s_Transform_Alloc(VALUE klass)
582 Transform *tp = ALLOC(Transform);
583 memset(tp, 0, sizeof(Transform));
584 (*tp)[0] = (*tp)[4] = (*tp)[8] = 1.0;
585 return Data_Wrap_Struct(klass, 0, -1, tp);
589 ValueFromTransform(Transform *tp)
592 VALUE val = s_Transform_Alloc(rb_cTransform);
593 Data_Get_Struct(val, Transform, tp1);
594 memmove(tp1, tp, sizeof(Transform));
604 * Returns a new Transform object.
606 * In the first form, an identity transform is returned.
608 * In the second form, the array must be either of the following
610 * (1) [[a11 a21 a31] [a12 a22 a32] [a13 a23 a33] [a14 a24 a34]]
611 * (2) [a11 a21 a31 a12 a22 a32 a13 a23 a33 a14 a24 a34]
612 * where [a11..a33] denotes the rotation part and [a14 a24 a34] denotes
613 * the translation part. All vectors in (1) are column vectors.
615 * In the third form, a new transform is built from a 3x4 matrix. The argument
616 * +matrix+ must respond to a method call <tt>matrix[col, row]</tt>
617 * where <tt>row</tt> is in <tt>0..2</tt> and <tt>col</tt> in <tt>0..3</tt>.
620 s_Transform_Initialize(int argc, VALUE *argv, VALUE self)
624 Data_Get_Struct(self, Transform, tp);
625 rb_scan_args(argc, argv, "01", &val);
627 TransformFromValue(val, tp);
632 s_Transform_NewFromTransform(Transform *tp)
635 VALUE retval = s_Transform_Alloc(rb_cTransform);
636 Data_Get_Struct(retval, Transform, tp1);
637 memmove(tp1, tp, sizeof(Transform));
643 * from_columns(c1, c2, c3, c4)
645 * Returns a new Transform object built from four column vectors. The arguments
646 * <tt>c1..c4</tt> are vectors of (at least) three-dimension. This is equivalent
647 * to <tt>Transform.new([c1, c2, c3, c4])</tt>.
650 s_Transform_NewFromColumns(VALUE klass, VALUE val)
655 static ID to_a_mid = 0;
657 to_a_mid = rb_intern("to_a");
658 if (TYPE(val) != T_ARRAY)
659 val = rb_funcall(val, to_a_mid, 0);
660 memset(tr, 0, sizeof(tr));
662 valp = RARRAY_PTR(val);
663 for (i = 0; i < 4; i++) {
667 w[0] = w[1] = w[2] = 0.0;
670 if (TYPE(val) != T_ARRAY)
671 val = rb_funcall(val, to_a_mid, 0);
672 nn = RARRAY_LEN(val);
673 valpp = RARRAY_PTR(val);
674 for (j = 0; j < 3 && j < nn; j++)
675 w[j] = NUM2DBL(rb_Float(valpp[j]));
677 for (j = 0; j < 3; j++)
678 tr[i * 3 + j] = w[j];
680 return s_Transform_NewFromTransform(&tr);
685 * from_rows(r1, r2, r3)
687 * Returns a new Transform object built from three row vectors. The arguments
688 * <tt>r1, r2, r3</tt> are vectors of (at least) four-dimension.
691 s_Transform_NewFromRows(VALUE klass, VALUE val)
696 static ID to_a_mid = 0;
698 to_a_mid = rb_intern("to_a");
699 if (TYPE(val) != T_ARRAY)
700 val = rb_funcall(val, to_a_mid, 0);
701 memset(tr, 0, sizeof(tr));
703 valp = RARRAY_PTR(val);
704 for (i = 0; i < 3; i++) {
708 w[0] = w[1] = w[2] = w[3] = 0.0;
711 if (TYPE(val) != T_ARRAY)
712 val = rb_funcall(val, to_a_mid, 0);
713 nn = RARRAY_LEN(val);
714 valpp = RARRAY_PTR(val);
715 for (j = 0; j < 4 && j < nn; j++)
716 w[j] = NUM2DBL(rb_Float(valpp[j]));
718 for (j = 0; j < 4; j++)
719 tr[j * 3 + i] = w[j];
721 return s_Transform_NewFromTransform(&tr);
726 * self[i, j] -> Float
728 * Get the element (+i+,+j+) of the transform matrix, i.e. column +i+, row +j+.
729 * Be careful about the order of the arguments. It follows convention of multi-dimensional arrays
730 * rather than mathematical notation.
733 s_Transform_ElementAtIndex(VALUE self, VALUE val1, VALUE val2)
737 int n1 = NUM2INT(val1);
738 int n2 = NUM2INT(val2);
739 Data_Get_Struct(self, Transform, tp);
740 if (n1 < 0 || n1 >= 4 || n2 < 0 || n2 >= 3)
741 rb_raise(rb_eMolbyError, "index to Transform out of range");
742 w = (*tp)[n1 * 3 + n2];
743 return rb_float_new(w);
750 * Set the element (+i+,+j+) of the transform matrix, i.e. column +i+, row +j+.
751 * Be careful about the order of the arguments. It follows convention of multi-dimensional arrays
752 * rather than mathematical notation.
755 s_Transform_SetElementAtIndex(VALUE self, VALUE idx1, VALUE idx2, VALUE val)
759 int n1 = NUM2INT(idx1);
760 int n2 = NUM2INT(idx2);
761 Data_Get_Struct(self, Transform, tp);
762 if (n1 < 0 || n1 >= 4 || n2 < 0 || n2 >= 3)
763 rb_raise(rb_eMolbyError, "index to Transform out of range");
764 w = NUM2DBL(rb_Float(val));
765 (*tp)[n1 * 3 + n2] = w;
766 return rb_float_new(w);
771 * self == val -> bool
773 * Returns +true+ if and only if all the corresponding elements are equal.
774 * Usual caution about the comparison of floating-point numbers should be paid.
777 s_Transform_IsEqual(VALUE self, VALUE val)
781 Data_Get_Struct(self, Transform, tp1);
782 TransformFromValue(val, &tr);
783 for (i = 0; i < 12; i++) {
784 if ((*tp1)[i] != tr[i])
792 * self + val -> (new) Transform
794 * Returns a new transform corresponding to the sum of the two transform matrix.
797 s_Transform_Add(VALUE self, VALUE val)
801 Data_Get_Struct(self, Transform, tp1);
802 TransformFromValue(val, &tr);
803 for (i = 0; i < 12; i++)
805 return s_Transform_NewFromTransform(&tr);
810 * self - val -> (new) Transform
812 * Returns a new transform corresponding to the difference of the two transform matrix.
815 s_Transform_Subtract(VALUE self, VALUE val)
819 Data_Get_Struct(self, Transform, tp1);
820 TransformFromValue(val, &tr);
821 for (i = 0; i < 12; i++)
822 tr[i] = (*tp1)[i] - tr[i];
823 return s_Transform_NewFromTransform(&tr);
828 * self * numeric -> (new) Transform
829 * self * Vector3D -> (new) Vector3D
830 * self * other_transform -> (new) Transform
832 * Perform the matrix multiplication. In the first form, a new matrix with scaled elements
833 * is returned. In the second, the transformed vector is returned. In the third form,
834 * the multiple of the two matrices is returned.
837 s_Transform_Multiply(VALUE self, VALUE val)
841 Data_Get_Struct(self, Transform, tp1);
842 if (rb_obj_is_kind_of(val, rb_cNumeric)) {
843 double w = NUM2DBL(rb_Float(val));
844 for (i = 0; i < 12; i++)
845 tr[i] = (*tp1)[i] * w;
846 return s_Transform_NewFromTransform(&tr);
848 static ID size_mid = 0;
850 size_mid = rb_intern("size");
851 if (rb_respond_to(val, size_mid) && NUM2INT(rb_funcall(val, size_mid, 0)) == 3) {
854 VectorFromValue(val, &v);
855 TransformVec(&v, *tp1, &v);
856 return ValueFromVector(&v);
859 TransformFromValue(val, &tr);
860 TransformMul(tr, *tp1, tr);
861 return s_Transform_NewFromTransform(&tr);
868 * identity -> Transform
870 * Returns an identity transform, <tt>[[1,0,0], [0,1,0], [0,0,1], [0,0,0]]</tt>.
873 s_Transform_Identity(VALUE klass)
876 memset(tr, 0, sizeof(tr));
877 tr[0] = tr[4] = tr[8] = 1.0;
878 return s_Transform_NewFromTransform(&tr);
885 * Returns a zero transform, <tt>[[0,0,0], [0,0,0], [0,0,0], [0,0,0]]</tt>.
888 s_Transform_Zero(VALUE klass)
891 memset(tr, 0, sizeof(tr));
892 return s_Transform_NewFromTransform(&tr);
898 * diagonal(f1, f2 = nil, f3 = nil)
900 * Returns a diagonal transform (the translational componets are all zero).
901 * In the first form, <tt>array[0], array[1], array[2]</tt> are for the
902 * x, y, z components, respectively. In the second form, <tt>f1, f2, f3</tt>
903 * are the x, y, z components. If <tt>f3</tt> is not given, the <tt>f2</tt>
904 * is used for the z components. If <tt>f2</tt> is not given, the <tt>f1</tt>
905 * is used for the y and z components.
908 s_Transform_Diagonal(int argc, VALUE *argv, VALUE klass)
911 VALUE arg1, arg2, arg3;
912 memset(tr, 0, sizeof(tr));
913 rb_scan_args(argc, argv, "12", &arg1, &arg2, &arg3);
914 if (TYPE(arg1) == T_ARRAY) {
918 len = RARRAY_LEN(arg1);
919 valp = RARRAY_PTR(arg1);
921 tr[0] = tr[4] = tr[8] = NUM2DBL(rb_Float(valp[0]));
923 tr[4] = tr[8] = NUM2DBL(rb_Float(valp[1]));
925 tr[8] = NUM2DBL(rb_Float(valp[2]));
927 tr[0] = tr[4] = tr[8] = NUM2DBL(rb_Float(arg1));
929 tr[4] = tr[8] = NUM2DBL(rb_Float(arg2));
931 tr[8] = NUM2DBL(rb_Float(arg3));
934 return s_Transform_NewFromTransform(&tr);
939 * inverse -> (new) Transform
941 * Returns the inverse transform. If the matrix is not regular, an exception is raised.
944 s_Transform_Inverse(VALUE self)
947 Data_Get_Struct(self, Transform, tp1);
948 if (TransformInvert(tr, *tp1))
949 rb_raise(rb_eMolbyError, "the transform matrix is not regular");
950 return s_Transform_NewFromTransform(&tr);
955 * self / val -> (new) Transform
957 * Returns self * val.invert. If val is not a regular transform,
958 * an exception is raised.
961 s_Transform_Divide(VALUE self, VALUE val)
964 Data_Get_Struct(self, Transform, tp1);
965 TransformFromValue(val, &tr);
966 if (TransformInvert(tr, tr))
967 rb_raise(rb_eMolbyError, "the transform matrix is not regular");
968 TransformMul(tr, *tp1, tr);
969 return s_Transform_NewFromTransform(&tr);
974 * transpose -> (new) Transform
976 * Returns a new transform in which the rotation component is transposed from the original.
979 s_Transform_Transpose(VALUE self)
982 Data_Get_Struct(self, Transform, tp1);
983 TransformTranspose(tr, *tp1);
984 return s_Transform_NewFromTransform(&tr);
989 * determinant -> Float
991 * Returns the determinant of the transform.
994 s_Transform_Determinant(VALUE self)
997 Data_Get_Struct(self, Transform, tp1);
998 return rb_float_new(TransformDeterminant(*tp1));
1005 * Returns the trace (sum of the diagonal elements) of the transform.
1008 s_Transform_Trace(VALUE self)
1011 Data_Get_Struct(self, Transform, tp1);
1012 return rb_float_new((*tp1)[0] + (*tp1)[4] + (*tp1)[8]);
1017 * column(index) -> Vector3D
1019 * Returns the index-th (0..3) column vector.
1022 s_Transform_Column(VALUE self, VALUE val)
1026 int n = NUM2INT(val);
1027 Data_Get_Struct(self, Transform, tp1);
1028 if (n < 0 || n >= 4)
1029 rb_raise(rb_eMolbyError, "row index out of range");
1030 v.x = (*tp1)[n * 3];
1031 v.y = (*tp1)[n * 3 + 1];
1032 v.z = (*tp1)[n * 3 + 2];
1033 return ValueFromVector(&v);
1038 * eigenvalues -> [[k1, k2, k3], v1, v2, v3]
1040 * Calculate the eigenvalues and eigenvectors. The matrix must be symmetric.
1043 s_Transform_Eigenvalues(VALUE self)
1049 Data_Get_Struct(self, Transform, tp1);
1050 if ((info = MatrixSymDiagonalize(*((Mat33 *)tp1), d, v)) != 0)
1051 rb_raise(rb_eMolbyError, "cannot diagonalize the given matrix: info = %d", info);
1052 return rb_ary_new3(4, rb_ary_new3(3, rb_float_new(d[0]), rb_float_new(d[1]), rb_float_new(d[2])), ValueFromVector(v), ValueFromVector(v + 1), ValueFromVector(v + 2));
1057 * Transform[*args] -> (new) Transform
1059 * Create a new transform. Equivalent to Transform.new(args).
1062 s_Transform_Create(VALUE klass, VALUE args)
1064 VALUE val = s_Transform_Alloc(klass);
1065 s_Transform_Initialize(1, &args, val);
1073 * Convert a transform to an array of 12 float numbers.
1076 s_Transform_ToArray(VALUE self)
1081 Data_Get_Struct(self, Transform, tp1);
1082 for (i = 0; i < 12; i++)
1083 val[i] = rb_float_new((*tp1)[i]);
1084 return rb_ary_new4(12, val);
1091 * Convert a transform to a string like
1092 * "Transform[[a11,a21,a31],[a12,a22,a32],[a13,a23,a33],[a14,a24,a34]]".
1095 s_Transform_Inspect(VALUE self)
1099 /* VALUE klass = CLASS_OF(self); */
1100 /* VALUE val = rb_funcall(klass, rb_intern("name"), 0); */
1101 VALUE val = rb_str_new2("Transform");
1102 ID mid = rb_intern("<<");
1103 ID mid2 = rb_intern("inspect");
1104 rb_str_cat(val, "[", 1);
1105 Data_Get_Struct(self, Transform, tp);
1106 for (i = 0; i < 4; i++) {
1107 rb_str_cat(val, "[", 1);
1108 for (j = 0; j < 3; j++) {
1110 f = (*tp)[i * 3 + j];
1111 rb_funcall(val, mid, 1, rb_funcall(rb_float_new(f), mid2, 0));
1113 rb_str_cat(val, ",", 1);
1115 rb_str_cat(val, "]", 1);
1117 rb_str_cat(val, ",", 1);
1119 rb_str_cat(val, "]", 1);
1125 * translation(vec) -> (new) Transform
1127 * Returns a transform corresponding to translation along the given vector. Equivalent
1128 * to <code>Transform[[1,0,0],[0,1,0],[0,0,1],vec]</code>.
1131 s_Transform_Translation(VALUE klass, VALUE vec)
1135 VALUE val = s_Transform_Alloc(klass);
1136 Data_Get_Struct(val, Transform, tp);
1137 VectorFromValue(vec, &v);
1146 * rotation(axis, angle, center = [0,0,0]) -> (new) Transform
1148 * Returns a transform corresponding to the rotation along the given axis and angle.
1149 * Angle is given in degree. If center is also given, that point will be the center of rotation.
1152 s_Transform_Rotation(int argc, VALUE *argv, VALUE klass)
1155 VALUE axis, angle, center;
1158 rb_scan_args(argc, argv, "21", &axis, &angle, ¢er);
1159 VectorFromValue(axis, &av);
1161 cv.x = cv.y = cv.z = 0.0;
1163 VectorFromValue(center, &cv);
1164 ang = NUM2DBL(rb_Float(angle)) * kDeg2Rad;
1165 if (TransformForRotation(tr, &av, ang, &cv))
1166 rb_raise(rb_eMolbyError, "rotation axis cannot be a zero vector");
1167 return ValueFromTransform(&tr);
1172 * reflection(axis, center = [0,0,0]) -> (new)Transform
1174 * Returns a transform corresponding to the reflection along the given axis. If
1175 * center is also given, that point will be fixed.
1178 s_Transform_Reflection(int argc, VALUE *argv, VALUE klass)
1183 rb_scan_args(argc, argv, "11", &axis, ¢er);
1184 VectorFromValue(axis, &av);
1186 cv.x = cv.y = cv.z = 0.0;
1188 VectorFromValue(center, &cv);
1189 if (TransformForReflection(tr, &av, &cv))
1190 rb_raise(rb_eMolbyError, "reflection axis cannot be a zero vector");
1191 return ValueFromTransform(&tr);
1196 * inversion(center = [0,0,0]) -> (new) Transform
1198 * Returns a transform corresponding to the inversion along the given point.
1201 s_Transform_Inversion(int argc, VALUE *argv, VALUE klass)
1206 rb_scan_args(argc, argv, "01", ¢er);
1208 cv.x = cv.y = cv.z = 0.0;
1210 VectorFromValue(center, &cv);
1211 TransformForInversion(tr, &cv);
1212 return ValueFromTransform(&tr);
1215 #pragma mark ====== IntGroup Class ======
1218 IntGroupFromValue(VALUE val)
1221 if (!rb_obj_is_kind_of(val, rb_cIntGroup))
1222 val = rb_funcall(rb_cIntGroup, rb_intern("new"), 1, val);
1223 Data_Get_Struct(val, IntGroup, ig);
1229 ValueFromIntGroup(IntGroup *ig)
1234 return Data_Wrap_Struct(rb_cIntGroup, 0, (void (*)(void *))IntGroupRelease, ig);
1238 IntGroup_RaiseIfError(int err)
1243 case kIntGroupStatusOutOfMemory: s = "out of memory"; break;
1244 case kIntGroupStatusOutOfRange: s = "out of range"; break;
1245 default: s = ""; break;
1247 rb_raise(rb_eMolbyError, "%s error occurred during IntGroup operation", s);
1253 IntGroup_Alloc(VALUE klass)
1255 IntGroup *ig = IntGroupNew();
1256 return Data_Wrap_Struct(klass, 0, (void (*)(void *))IntGroupRelease, ig);
1259 /* Iterator block for initializer */
1261 s_IntGroup_Initialize_i(VALUE val, VALUE ig1)
1263 IntGroup_RaiseIfError(IntGroupAdd((IntGroup *)ig1, NUM2INT(val), 1));
1269 * new(arg1, arg2,...)
1270 * new(arg1, arg2,...) {|i| ...}
1272 * Create a new integer group. If no arguments are given, an empty group is returned.
1273 * The arguments are either IntGroup, Range, Enumerable, or Numeric. In either case,
1274 * the non-negative integers included in the arguments are added to the result.
1275 * If a block is given, the block is called with the each integer in the given arguments,
1276 * and the integer group consisting with the returned integers is returned.
1279 s_IntGroup_Initialize(int argc, VALUE *argv, VALUE self)
1282 Data_Get_Struct(self, IntGroup, ig1);
1283 while (argc-- > 0) {
1284 VALUE arg = *argv++;
1285 int type = TYPE(arg);
1286 if (rb_obj_is_kind_of(arg, rb_cIntGroup))
1287 rb_funcall(rb_cIntGroup, rb_intern("merge"), 1, arg);
1288 else if (rb_obj_is_kind_of(arg, rb_cRange)) {
1290 sp = NUM2INT(rb_funcall(arg, rb_intern("begin"), 0));
1291 ep = NUM2INT(rb_funcall(arg, rb_intern("end"), 0));
1292 if (RTEST(rb_funcall(arg, rb_intern("exclude_end?"), 0)))
1295 IntGroup_RaiseIfError(IntGroupAdd(ig1, sp, ep - sp + 1));
1296 } else if (rb_respond_to(arg, rb_intern("each")) && type != T_STRING)
1297 rb_iterate(rb_each, arg, s_IntGroup_Initialize_i, (VALUE)ig1);
1299 IntGroup_RaiseIfError(IntGroupAdd(ig1, NUM2INT(arg), 1));
1301 if (rb_block_given_p()) {
1302 IntGroup *ig2 = IntGroupNew();
1304 for (i = 0; (n = IntGroupGetNthPoint(ig1, i)) >= 0; i++) {
1305 n = NUM2INT(rb_yield(INT2NUM(n)));
1307 IntGroup_RaiseIfError(IntGroupAdd(ig2, n, 1));
1309 IntGroup_RaiseIfError(IntGroupCopy(ig1, ig2));
1318 * Discard all integers included in self.
1321 s_IntGroup_Clear(VALUE self)
1324 Data_Get_Struct(self, IntGroup, ig);
1331 * dup(IntGroup) -> (new) IntGroup
1333 * (Deep) copy the given IntGroup.
1336 s_IntGroup_InitializeCopy(VALUE self, VALUE val)
1338 IntGroup *ig1, *ig2;
1339 Data_Get_Struct(self, IntGroup, ig1);
1340 if (!rb_obj_is_kind_of(val, rb_cIntGroup))
1341 rb_raise(rb_eMolbyError, "IntGroup instance is expected");
1342 Data_Get_Struct(val, IntGroup, ig2);
1343 IntGroupCopy(ig1, ig2);
1352 * Returns the number of integers included in self.
1355 s_IntGroup_Length(VALUE self)
1358 Data_Get_Struct(self, IntGroup, ig);
1359 return INT2NUM(IntGroupGetCount(ig));
1364 * member?(val) -> bool
1365 * include?(val) -> bool
1367 * Check whether the val is included in self.
1370 s_IntGroup_MemberP(VALUE self, VALUE val)
1373 int n = NUM2INT(val);
1374 Data_Get_Struct(self, IntGroup, ig);
1375 return (IntGroupLookup(ig, n, NULL) ? Qtrue : Qfalse);
1380 * self[index] -> Integer or nil
1382 * Get the index-th point in self. If the index is out of range, nil is returned.
1385 s_IntGroup_ElementAtIndex(VALUE self, VALUE val)
1389 int index = NUM2INT(rb_Integer(val));
1390 Data_Get_Struct(self, IntGroup, ig);
1391 n = IntGroupGetNthPoint(ig, index);
1392 return (n >= 0 ? INT2NUM(n) : Qnil);
1399 * Call the block with each integer in self.
1402 s_IntGroup_Each(VALUE self)
1406 Data_Get_Struct(self, IntGroup, ig);
1407 for (i = 0; (sp = IntGroupGetStartPoint(ig, i)) >= 0; i++) {
1408 ep = IntGroupGetEndPoint(ig, i);
1409 for (j = sp; j < ep; j++) {
1410 rb_yield(INT2NUM(j));
1418 * add(IntGroup) -> self
1420 * Add the points in the given group.
1423 s_IntGroup_Add(VALUE self, VALUE val)
1426 if (OBJ_FROZEN(self))
1427 rb_error_frozen("IntGroup");
1428 Data_Get_Struct(self, IntGroup, ig);
1429 if (rb_obj_is_kind_of(val, rb_cNumeric)) {
1430 int n = NUM2INT(rb_Integer(val));
1432 rb_raise(rb_eMolbyError, "the integer group can contain only non-negative values");
1433 IntGroupAdd(ig, n, 1);
1435 ig2 = IntGroupFromValue(val);
1436 IntGroupAddIntGroup(ig, ig2);
1437 IntGroupRelease(ig2);
1444 * delete(IntGroup) -> self
1446 * Remove the points in the given group.
1449 s_IntGroup_Delete(VALUE self, VALUE val)
1452 if (OBJ_FROZEN(self))
1453 rb_error_frozen("IntGroup");
1454 Data_Get_Struct(self, IntGroup, ig);
1455 if (rb_obj_is_kind_of(val, rb_cNumeric)) {
1456 int n = NUM2INT(rb_Integer(val));
1457 if (n >= 0 && IntGroupLookup(ig, n, NULL))
1458 IntGroupRemove(ig, n, 1);
1460 ig2 = IntGroupFromValue(val);
1461 IntGroupRemoveIntGroup(ig, ig2);
1462 IntGroupRelease(ig2);
1468 s_IntGroup_Binary(VALUE self, VALUE val, int (*func)(const IntGroup *, const IntGroup *, IntGroup *))
1470 IntGroup *ig1, *ig2, *ig3;
1472 Data_Get_Struct(self, IntGroup, ig1);
1473 ig2 = IntGroupFromValue(val);
1474 retval = IntGroup_Alloc(rb_cIntGroup);
1475 Data_Get_Struct(retval, IntGroup, ig3);
1476 IntGroup_RaiseIfError(func(ig1, ig2, ig3));
1477 IntGroupRelease(ig2);
1483 * union(val) -> (new)IntGroup
1484 * self + val -> (new)IntGroup
1485 * self | val -> (new)IntGroup
1487 * Returns a union group.
1490 s_IntGroup_Union(VALUE self, VALUE val)
1492 return s_IntGroup_Binary(self, val, IntGroupUnion);
1497 * intersection(val) -> (new)IntGroup
1498 * self & val -> (new)IntGroup
1500 * Returns an intersection group.
1503 s_IntGroup_Intersection(VALUE self, VALUE val)
1505 return s_IntGroup_Binary(self, val, IntGroupIntersect);
1510 * difference(val) -> (new)IntGroup
1511 * self - val -> (new)IntGroup
1513 * Returns a difference group.
1516 s_IntGroup_Difference(VALUE self, VALUE val)
1518 return s_IntGroup_Binary(self, val, IntGroupDifference);
1523 * sym_difference(val) -> (new)IntGroup
1524 * self ^ val -> (new)IntGroup
1526 * Returns a symmetric-difference group (i.e. a group containing elements that are included
1527 * in either self or val but not both).
1530 s_IntGroup_SymDifference(VALUE self, VALUE val)
1532 return s_IntGroup_Binary(self, val, IntGroupXor);
1537 * convolute(val) -> (new)IntGroup
1539 * For each element n in self, get the n-th point in val, and return the result as a new group.
1540 * If n is out of range, then that point is ignored.
1542 * <b>See Also:</b> IntGroup#deconvolute. If all points in self are within the range of val, then
1543 * an equation <tt>self.convolute(val).deconvolute(val) == self</tt> holds.
1546 s_IntGroup_Convolute(VALUE self, VALUE val)
1548 return s_IntGroup_Binary(self, val, IntGroupConvolute);
1553 * deconvolute(val) -> (new)IntGroup
1555 * For each element n in self, find the point n in val, and return the found indices as a new group.
1556 * If n is not found in val, then that point is ignored.
1558 * <b>See Also:</b> IntGroup#convolute. If all points in self are found in val, then
1559 * an equation <tt>self.deconvolute(val).convolute(val) == self</tt> holds.
1562 s_IntGroup_Deconvolute(VALUE self, VALUE val)
1564 return s_IntGroup_Binary(self, val, IntGroupDeconvolute);
1569 * range_at(val) -> Range
1571 * Split self into consecutive chunks of integers, and return the val-th chunk as a Range.
1572 * This method is relatively efficient, because it directly uses the internal representation
1576 s_IntGroup_RangeAt(VALUE self, VALUE val)
1579 int n = NUM2INT(val);
1581 Data_Get_Struct(self, IntGroup, ig);
1582 sp = IntGroupGetStartPoint(ig, n);
1585 ep = IntGroupGetEndPoint(ig, n) - 1;
1586 return rb_funcall(rb_cRange, rb_intern("new"), 2, INT2NUM(sp), INT2NUM(ep));
1591 s_IntGroup_Merge(VALUE self, VALUE val)
1593 IntGroup *ig1, *ig2;
1594 int i, sp, interval;
1595 if (OBJ_FROZEN(self))
1596 rb_error_frozen("IntGroup");
1597 Data_Get_Struct(self, IntGroup, ig1);
1598 ig2 = IntGroupFromValue(val);
1599 for (i = 0; (sp = IntGroupGetStartPoint(ig2, i)) >= 0; i++) {
1600 interval = IntGroupGetInterval(ig2, i);
1601 IntGroup_RaiseIfError(IntGroupAdd(ig1, sp, interval));
1603 IntGroupRelease(ig2);
1608 s_IntGroup_Subtract(VALUE self, VALUE val)
1610 IntGroup *ig1, *ig2;
1611 int i, sp, interval;
1612 if (OBJ_FROZEN(self))
1613 rb_error_frozen("IntGroup");
1614 Data_Get_Struct(self, IntGroup, ig1);
1615 ig2 = IntGroupFromValue(val);
1616 for (i = 0; (sp = IntGroupGetStartPoint(ig2, i)) >= 0; i++) {
1617 interval = IntGroupGetInterval(ig2, i);
1618 IntGroup_RaiseIfError(IntGroupRemove(ig1, sp, interval));
1620 IntGroupRelease(ig2);
1627 * offset(val) -> self
1629 * Move all points by an integer value. A negative val is allowed, but it
1630 * must be no smaller than -(self[0]), otherwise an exception is thrown.
1633 s_IntGroup_Offset(VALUE self, VALUE ofs)
1635 IntGroup *ig1, *ig2;
1638 Data_Get_Struct(self, IntGroup, ig1);
1639 ig2 = IntGroupNewFromIntGroup(ig1);
1641 rb_raise(rb_eMolbyError, "Cannot duplicate IntGroup");
1642 iofs = NUM2INT(ofs);
1643 if (IntGroupOffset(ig2, iofs) != 0)
1644 rb_raise(rb_eMolbyError, "Bad offset %d", iofs);
1645 val = ValueFromIntGroup(ig2);
1646 IntGroupRelease(ig2);
1651 s_IntGroup_Create(int argc, VALUE *argv, VALUE klass)
1653 VALUE val = IntGroup_Alloc(klass);
1654 s_IntGroup_Initialize(argc, argv, val);
1662 * Create a String in the form "IntGroup[...]".
1665 s_IntGroup_Inspect(VALUE self)
1670 /* VALUE klass = CLASS_OF(self);
1671 VALUE val = rb_funcall(klass, rb_intern("name"), 0); */
1672 /* rb_str_cat(val, "[", 1); */
1673 VALUE val = rb_str_new2("IntGroup[");
1674 Data_Get_Struct(self, IntGroup, ig);
1675 for (i = 0; (sp = IntGroupGetStartPoint(ig, i)) >= 0; i++) {
1677 rb_str_cat(val, ", ", 2);
1678 ep = IntGroupGetEndPoint(ig, i);
1680 snprintf(buf, sizeof buf, "%d..%d", sp, ep - 1);
1682 snprintf(buf, sizeof buf, "%d", sp);
1683 rb_str_cat(val, buf, strlen(buf));
1685 rb_str_cat(val, "]", 1);
1690 Init_MolbyTypes(void)
1692 /* class Vector3D */
1693 rb_cVector3D = rb_define_class_under(rb_mMolby, "Vector3D", rb_cObject);
1694 rb_define_alloc_func(rb_cVector3D, s_Vector3D_Alloc);
1695 rb_define_method(rb_cVector3D, "initialize", s_Vector3D_Initialize, -1);
1696 rb_define_method(rb_cVector3D, "size", s_Vector3D_Size, 0);
1697 rb_define_method(rb_cVector3D, "[]", s_Vector3D_ElementAtIndex, 1);
1698 rb_define_method(rb_cVector3D, "[]=", s_Vector3D_SetElementAtIndex, 2);
1699 rb_define_method(rb_cVector3D, "==", s_Vector3D_IsEqual, 1);
1700 rb_define_method(rb_cVector3D, "+", s_Vector3D_Add, 1);
1701 rb_define_method(rb_cVector3D, "-", s_Vector3D_Subtract, 1);
1702 rb_define_method(rb_cVector3D, "*", s_Vector3D_Multiply, 1);
1703 rb_define_method(rb_cVector3D, "/", s_Vector3D_Divide, 1);
1704 rb_define_method(rb_cVector3D, "dot", s_Vector3D_Dot, 1);
1705 rb_define_method(rb_cVector3D, "cross", s_Vector3D_Cross, 1);
1706 rb_define_method(rb_cVector3D, "-@", s_Vector3D_UnaryMinus, 0);
1707 rb_define_method(rb_cVector3D, "length", s_Vector3D_Length, 0);
1708 rb_define_alias(rb_cVector3D, "r", "length"); /* size and length are not synonym! */
1709 rb_define_method(rb_cVector3D, "length2", s_Vector3D_Length2, 0);
1710 rb_define_alias(rb_cVector3D, "r2", "length2");
1711 rb_define_method(rb_cVector3D, "normalize", s_Vector3D_Normalize, 0);
1712 rb_define_method(rb_cVector3D, "to_a", s_Vector3D_ToArray, 0);
1713 rb_define_method(rb_cVector3D, "each", s_Vector3D_Each, 0);
1714 rb_define_method(rb_cVector3D, "x", s_Vector3D_GetX, 0);
1715 rb_define_method(rb_cVector3D, "y", s_Vector3D_GetY, 0);
1716 rb_define_method(rb_cVector3D, "z", s_Vector3D_GetZ, 0);
1717 rb_define_method(rb_cVector3D, "x=", s_Vector3D_SetX, 1);
1718 rb_define_method(rb_cVector3D, "y=", s_Vector3D_SetY, 1);
1719 rb_define_method(rb_cVector3D, "z=", s_Vector3D_SetZ, 1);
1720 rb_define_method(rb_cVector3D, "inspect", s_Vector3D_Inspect, 0);
1721 rb_define_alias(rb_cVector3D, "to_s", "inspect");
1722 rb_define_singleton_method(rb_cVector3D, "[]", s_Vector3D_Create, -2);
1724 /* class Transform */
1725 rb_cTransform = rb_define_class_under(rb_mMolby, "Transform", rb_cObject);
1726 rb_define_alloc_func(rb_cTransform, s_Transform_Alloc);
1727 rb_define_method(rb_cTransform, "initialize", s_Transform_Initialize, -1);
1728 rb_define_method(rb_cTransform, "[]", s_Transform_ElementAtIndex, 2);
1729 rb_define_method(rb_cTransform, "[]=", s_Transform_SetElementAtIndex, 3);
1730 rb_define_method(rb_cTransform, "==", s_Transform_IsEqual, 1);
1731 rb_define_method(rb_cTransform, "+", s_Transform_Add, 1);
1732 rb_define_method(rb_cTransform, "-", s_Transform_Subtract, 1);
1733 rb_define_method(rb_cTransform, "*", s_Transform_Multiply, 1);
1734 rb_define_method(rb_cTransform, "/", s_Transform_Divide, 1);
1735 rb_define_method(rb_cTransform, "inverse", s_Transform_Inverse, 0);
1736 rb_define_method(rb_cTransform, "transpose", s_Transform_Transpose, 0);
1737 rb_define_method(rb_cTransform, "determinant", s_Transform_Determinant, 0);
1738 rb_define_method(rb_cTransform, "trace", s_Transform_Trace, 0);
1739 rb_define_method(rb_cTransform, "column", s_Transform_Column, 1);
1740 rb_define_method(rb_cTransform, "eigenvalues", s_Transform_Eigenvalues, 0);
1741 rb_define_method(rb_cTransform, "to_a", s_Transform_ToArray, 0);
1742 rb_define_method(rb_cTransform, "inspect", s_Transform_Inspect, 0);
1743 rb_define_alias(rb_cTransform, "to_s", "inspect");
1744 rb_define_singleton_method(rb_cTransform, "diagonal", s_Transform_Diagonal, -1);
1745 rb_define_singleton_method(rb_cTransform, "[]", s_Transform_Create, -2);
1746 rb_define_singleton_method(rb_cTransform, "from_columns", s_Transform_NewFromColumns, -2);
1747 rb_define_singleton_method(rb_cTransform, "from_rows", s_Transform_NewFromRows, -2);
1748 rb_define_singleton_method(rb_cTransform, "identity", s_Transform_Identity, 0);
1749 rb_define_singleton_method(rb_cTransform, "zero", s_Transform_Zero, 0);
1750 rb_define_singleton_method(rb_cTransform, "translation", s_Transform_Translation, 1);
1751 rb_define_singleton_method(rb_cTransform, "rotation", s_Transform_Rotation, -1);
1752 rb_define_singleton_method(rb_cTransform, "reflection", s_Transform_Reflection, -1);
1753 rb_define_singleton_method(rb_cTransform, "inversion", s_Transform_Inversion, -1);
1755 /* class IntGroup */
1756 rb_cIntGroup = rb_define_class_under(rb_mMolby, "IntGroup", rb_cObject);
1757 rb_include_module(rb_cIntGroup, rb_mEnumerable);
1758 rb_define_alloc_func(rb_cIntGroup, IntGroup_Alloc);
1759 rb_define_method(rb_cIntGroup, "clear", s_IntGroup_Clear, 0);
1760 rb_define_method(rb_cIntGroup, "initialize", s_IntGroup_Initialize, -1);
1761 rb_define_method(rb_cIntGroup, "initialize_copy", s_IntGroup_InitializeCopy, 1);
1762 rb_define_method(rb_cIntGroup, "length", s_IntGroup_Length, 0);
1763 rb_define_alias(rb_cIntGroup, "size", "length");
1764 rb_define_method(rb_cIntGroup, "member?", s_IntGroup_MemberP, 1);
1765 rb_define_alias(rb_cIntGroup, "include?", "member?");
1766 rb_define_method(rb_cIntGroup, "each", s_IntGroup_Each, 0);
1767 rb_define_method(rb_cIntGroup, "[]", s_IntGroup_ElementAtIndex, 1);
1768 rb_define_method(rb_cIntGroup, "add", s_IntGroup_Add, 1);
1769 rb_define_alias(rb_cIntGroup, "<<", "add");
1770 rb_define_method(rb_cIntGroup, "delete", s_IntGroup_Delete, 1);
1771 rb_define_method(rb_cIntGroup, "union", s_IntGroup_Union, 1);
1772 rb_define_method(rb_cIntGroup, "difference", s_IntGroup_Difference, 1);
1773 rb_define_method(rb_cIntGroup, "intersection", s_IntGroup_Intersection, 1);
1774 rb_define_method(rb_cIntGroup, "sym_difference", s_IntGroup_SymDifference, 1);
1775 rb_define_method(rb_cIntGroup, "convolute", s_IntGroup_Convolute, 1);
1776 rb_define_method(rb_cIntGroup, "deconvolute", s_IntGroup_Deconvolute, 1);
1777 rb_define_method(rb_cIntGroup, "offset", s_IntGroup_Offset, 1);
1778 rb_define_alias(rb_cIntGroup, "+", "union");
1779 rb_define_alias(rb_cIntGroup, "|", "union");
1780 rb_define_alias(rb_cIntGroup, "-", "difference");
1781 rb_define_alias(rb_cIntGroup, "&", "intersection");
1782 rb_define_alias(rb_cIntGroup, "^", "sym_difference");
1783 rb_define_method(rb_cIntGroup, "range_at", s_IntGroup_RangeAt, 1);
1784 /* rb_define_method(rb_cIntGroup, "merge", s_IntGroup_Merge, -1);
1785 rb_define_method(rb_cIntGroup, "subtract", s_IntGroup_Subtract, -1); */
1786 rb_define_method(rb_cIntGroup, "inspect", s_IntGroup_Inspect, 0);
1787 rb_define_alias(rb_cIntGroup, "to_s", "inspect");
1788 rb_define_singleton_method(rb_cIntGroup, "[]", s_IntGroup_Create, -1);
1790 VALUE igval = IntGroup_Alloc(rb_cIntGroup);
1792 Data_Get_Struct(igval, IntGroup, ig);
1793 IntGroupAdd(ig, 0, ATOMS_MAX_NUMBER);
1794 rb_define_global_const("All", igval);