Skip to content

Commit 1a6be5e

Browse files
committed
move Transform class to a new file
1 parent d3697ab commit 1a6be5e

File tree

3 files changed

+302
-296
lines changed

3 files changed

+302
-296
lines changed

glutil-transform.js

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/*
2+
Written by Peter O. in 2015.
3+
4+
Any copyright is dedicated to the Public Domain.
5+
http://creativecommons.org/publicdomain/zero/1.0/
6+
If you like this, you should donate to Peter O.
7+
at: http://upokecenter.dreamhosters.com/articles/donate-now-2/
8+
*/
9+
10+
/**
11+
* A class offering a convenient way to set a transformation
12+
* from one coordinate system to another.
13+
* @class
14+
* @alias glutil.Transform
15+
*/
16+
function Transform(){
17+
/**
18+
* A three-element array giving the scaling for an object's width,
19+
* height, and depth, respectively.
20+
* For each component, 1 means no scaling.
21+
* The value given here is informational only and should not be modified directly.
22+
* Use the setScale method to set this value.
23+
* @default
24+
*/
25+
this.scale=[1,1,1];
26+
/**
27+
* A three-element array giving the X, Y, and Z coordinates of the position
28+
* of an object relative to its original position.
29+
* The value given here is informational only and should not be modified directly.
30+
* Use the setPosition method to set this value.
31+
* @default
32+
*/
33+
this.position=[0,0,0];
34+
/**
35+
* The rotation of an object in the form of a [quaternion]{@link glmath.GLMath}.
36+
* The value given here is informational only and should not be modified directly.
37+
* Use the setOrientation or setQuaternion method to set this value.
38+
*/
39+
this.rotation=GLMath.quatIdentity();
40+
this.complexMatrix=false;
41+
this._matrixDirty=false;
42+
/** @private */
43+
this.matrix=GLMath.mat4identity();
44+
}
45+
46+
/**
47+
* Sets this shape's transformation matrix. This method
48+
* will set the position, rotation, and scale properties
49+
* accordingly to the matrix given.
50+
* @param {Array<number>} value A 4x4 matrix.
51+
* This method will copy the value of this parameter.
52+
* @return {glutil.Transform} This object.
53+
*/
54+
Transform.prototype.setMatrix=function(value){
55+
this._matrixDirty=false;
56+
this.complexMatrix=true;
57+
this.matrix=value.slice(0,16);
58+
this.position=[this.matrix[12],this.matrix[13],this.matrix[14]];
59+
this.rotation=GLMath.quatFromMat4(this.matrix);
60+
this.rotation=GLMath.quatNormInPlace(this.rotation);
61+
this.scale=[this.matrix[0],this.matrix[5],this.matrix[10]];
62+
return this;
63+
}
64+
65+
/**
66+
* Resets this transform to the untransformed state.
67+
* @return {glutil.Transform} This object.
68+
*/
69+
Transform.prototype.resetTransform=function(){
70+
this.matrix=GLMath.mat4identity();
71+
this.position=[0,0,0];
72+
this.scale=[1,1,1];
73+
this.rotation=GLMath.quatIdentity();
74+
this.complexMatrix=false;
75+
this._matrixDirty=false;
76+
return this;
77+
}
78+
/**
79+
* Sets the scale of an object relative to its original
80+
* size. Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
81+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
82+
* @param {number|Array<number>} x Scaling factor for this object's width.
83+
* If "y" and "z" are null or omitted, this can
84+
* instead be a 3-element array giving the scaling factors
85+
* for width, height, and depth, respectively.
86+
* @param {number} y Scaling factor for this object's height.
87+
* @param {number} z Scaling factor for this object's depth.
88+
* @return {glutil.Transform} This object.
89+
*/
90+
Transform.prototype.setScale=function(x,y,z){
91+
if(this.complexMatrix)return this;
92+
if(x!=null && y==null && z==null){
93+
if(x.constructor==Array)
94+
this.scale=x.slice(0,3);
95+
else
96+
this.scale=[x,x,x];
97+
} else {
98+
this.scale=[x,y,z];
99+
}
100+
this._matrixDirty=true;
101+
return this;
102+
}
103+
/**
104+
* Sets the relative position of an object from its original
105+
* position. Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
106+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
107+
* @param {Array<number>|number} x Either the X-coordinate,
108+
* or an array of 3 numbers giving the x, y, and z coordinates.
109+
* @param {number} y The Y-coordinate.
110+
* If "x" is an array, this parameter may be omitted.
111+
* @param {number} z The Z-coordinate.
112+
* If "x" is an array, this parameter may be omitted.
113+
* @return {glutil.Transform} This object.
114+
*/
115+
Transform.prototype.setPosition=function(x,y,z){
116+
if(this.complexMatrix)return this;
117+
if(x!=null && y==null && z==null){
118+
if(x.constructor==Array)
119+
this.position=x.slice(0,3);
120+
else
121+
this.position=[x,x,x];
122+
} else {
123+
this.position=[x,y,z];
124+
}
125+
this._matrixDirty=true;
126+
return this;
127+
}
128+
/**
129+
* Sets this object's orientation in the form of a [quaternion]{@link glmath.GLMath} (a 4-element array
130+
* for describing 3D rotations). Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
131+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
132+
* @param {Array<number>} quat A four-element array describing the rotation.
133+
* A quaternion is returned from the methods {@link glmath.GLMath.quatFromAxisAngle}
134+
* and {@link glmath.GLMath.quatFromTaitBryan}, among others.
135+
* @return {glutil.Transform} This object.
136+
* @example
137+
* // Set an object's orientation to 30 degrees about the X-axis
138+
* transform.setQuaternion(GLMath.quatFromAxisAngle(20,1,0,0));
139+
* // Set an object's orientation to identity (no rotation)
140+
* transform.setQuaternion(GLMath.quatIdentity());
141+
* // Set an object's orientation to 30 degree pitch multiplied
142+
* // by 40 degree roll
143+
* transform.setQuaternion(GLMath.quatFromTaitBryan(30,0,40));
144+
*/
145+
Transform.prototype.setQuaternion=function(quat){
146+
if(this.complexMatrix)return this;
147+
this.rotation=quat.slice(0,4);
148+
GLMath.quatNormInPlace(this.rotation);
149+
this._matrixDirty=true;
150+
return this;
151+
}
152+
/**
153+
* Sets this object's orientation in the form of an angle and an axis of
154+
* rotation. Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
155+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
156+
* @param {Array<number>|number} angle The desired angle
157+
* to rotate in degrees. If "v", "vy", and "vz" are omitted, this can
158+
* instead be a 4-element array giving the axis
159+
* of rotation as the first three elements, followed by the angle
160+
* in degrees as the fourth element. If the axis of rotation
161+
* points toward the viewer, the angle's value is increasing in
162+
* a counterclockwise direction.
163+
* @param {Array<number>|number} v X-component of the axis
164+
* of rotation. If "vy" and "vz" are omitted, this can
165+
* instead be a 3-element array giving the axis
166+
* of rotation in x, y, and z, respectively.
167+
* @param {number} vy Y-component of the axis
168+
* of rotation.
169+
* @param {number} vz Z-component of the axis
170+
* of rotation.
171+
* @return {glutil.Transform} This object.
172+
*/
173+
Transform.prototype.setOrientation=function(angle, v,vy,vz){
174+
return this.setQuaternion(GLMath.quatFromAxisAngle(angle,v,vy,vz));
175+
}
176+
/**
177+
* Combines an object's current rotation with another rotation
178+
* described by a [quaternion]{@link glmath.GLMath} (a 4-element array
179+
* for describing 3D rotations). The combined rotation will have the
180+
* same effect as the new rotation followed by the existing rotation.
181+
* Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
182+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
183+
* @param {Array<number>} quat A four-element array describing the rotation.
184+
* A quaternion is returned from the methods {@link glmath.GLMath.quatFromAxisAngle}
185+
* or {@link glmath.GLMath.quatFromTaitBryan}.
186+
* @return {glutil.Transform} This object.
187+
* @example
188+
* // Combine an object's orientation with a rotation 20 degrees about the X-axis
189+
* transform.multQuaternion(GLMath.quatFromAxisAngle(20,1,0,0));
190+
* // Combine an object's orientation with identity (no rotation)
191+
* transform.multQuaternion(GLMath.quatIdentity());
192+
* // Combine an object's orientation with 30 degree pitch multiplied
193+
* // by 40 degree roll
194+
* transform.multQuaternion(GLMath.quatFromTaitBryan(30,0,40));
195+
*/
196+
Transform.prototype.multQuaternion=function(quat){
197+
if(this.complexMatrix)return this;
198+
this.rotation=GLMath.quatMultiply(this.rotation,quat);
199+
GLMath.quatNormInPlace(this.rotation);
200+
this._matrixDirty=true;
201+
return this;
202+
}
203+
/**
204+
* Combines an object's current rotation with another rotation
205+
* in the form of an angle and an axis of
206+
* rotation. The combined rotation will have the
207+
* same effect as the new rotation followed by the existing rotation.
208+
* Has no effect if a matrix was defined with {@link glutil.Transform#setMatrix}
209+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
210+
* @param {Array<number>|number} angle The desired angle
211+
* to rotate in degrees. See {@link glutil.Transform#setOrientation}.
212+
* @param {Array<number>|number} v X-component of the axis
213+
* of rotation. If "vy" and "vz" are omitted, this can
214+
* instead be a 3-element array giving the axis
215+
* of rotation in x, y, and z, respectively.
216+
* @param {number} vy Y-component of the axis
217+
* of rotation.
218+
* @param {number} vz Z-component of the axis
219+
* of rotation.
220+
* @return {glutil.Transform} This object.
221+
*/
222+
Transform.prototype.multOrientation=function(angle, v,vy,vz){
223+
return this.multQuaternion(GLMath.quatFromAxisAngle(angle,v,vy,vz));
224+
}
225+
/**
226+
* Gets the transformation matrix used by an object. It is a combination
227+
* of the scale, position, and rotation properties,
228+
* unless a matrix was defined with {@link glutil.Transform#setMatrix}
229+
* and the transform wasn't reset yet with {@link glutil.Transform#resetTransform}.
230+
* @return {Array<number>}
231+
*/
232+
Transform.prototype.getMatrix=function(){
233+
if(this._matrixDirty){
234+
this._matrixDirty=false;
235+
// for best results, multiply in this order:
236+
// 1. translation
237+
this.matrix=GLMath.mat4translated(this.position[0],
238+
this.position[1],this.position[2]);
239+
// 2. rotation
240+
if(!GLMath.quatIsIdentity(this.rotation)){
241+
this.matrix=GLMath.mat4multiply(this.matrix,
242+
GLMath.quatToMat4(this.rotation));
243+
}
244+
// 3. scaling
245+
GLMath.mat4scaleInPlace(this.matrix,this.scale);
246+
}
247+
return this.matrix.slice(0,16);
248+
}
249+
250+
/**
251+
* Makes a copy of this object. The copied object
252+
* will have its own version of the rotation, scale,
253+
* position, and matrix data.
254+
* @return {glutil.Transform} A copy of this object.
255+
*/
256+
Transform.prototype.copy=function(){
257+
var ret=new Transform();
258+
ret.scale=this.scale.slice(0,this.scale.length);
259+
ret.position=this.position.slice(0,this.scale.length);
260+
ret.complexMatrix=this.complexMatrix;
261+
ret._matrixDirty=this._matrixDirty;
262+
ret.matrix=this.matrix.slice(0,this.matrix.length);
263+
return ret;
264+
}

0 commit comments

Comments
 (0)