1
- import { vec3 , mat4 } from 'gl-matrix' ;
1
+ import { vec3 , mat4 , quat } from 'gl-matrix' ;
2
2
import { degrees2radians } from '../lib/math/angles.js' ;
3
3
import EVENTS from '../events.js' ;
4
4
@@ -32,47 +32,66 @@ export default class {
32
32
} else {
33
33
this . _state = JSON . parse ( JSON . stringify ( state ) ) ;
34
34
}
35
+
36
+ // copy the state to a cache, so we can modify internally,
37
+ // but remember the original values for absolute rotations
38
+ this . _state . cache = {
39
+ ...this . _state ,
40
+ } ;
35
41
}
36
42
37
43
getEventWindow = ( ) => {
38
44
return this . eventWindow ;
39
45
} ;
40
46
41
- rotate = ( dThetaX , dThetaY ) => {
47
+ _rotate = ( viewUp , sliceNormal , dThetaX , dThetaY , dThetaZ = 0 ) => {
42
48
validateNumber ( dThetaX ) ;
43
49
validateNumber ( dThetaY ) ;
50
+ validateNumber ( dThetaZ ) ;
44
51
45
52
let xAxis = [ ] ;
46
- vec3 . cross ( xAxis , this . _state . viewUp , this . _state . sliceNormal ) ;
53
+ vec3 . cross ( xAxis , viewUp , sliceNormal ) ;
47
54
vec3 . normalize ( xAxis , xAxis ) ;
48
55
49
- let yAxis = this . _state . viewUp ;
56
+ let yAxis = viewUp ;
50
57
// rotate around the vector of the cross product of the
51
58
// plane and viewup as the X component
52
59
53
- const sliceNormal = [ ] ;
54
- const sliceViewUp = [ ] ;
60
+ const nSliceNormal = [ ] ;
61
+ const nViewUp = [ ] ;
55
62
56
63
const planeMat = mat4 . create ( ) ;
57
64
58
- //Rotate around the vertical (slice-up) vector
65
+ // Rotate around the vertical (slice-up) vector
59
66
mat4 . rotate ( planeMat , planeMat , degrees2radians ( dThetaY ) , yAxis ) ;
60
67
61
- //Rotate around the horizontal (screen-x) vector
68
+ // Rotate around the horizontal (screen-x) vector
62
69
mat4 . rotate ( planeMat , planeMat , degrees2radians ( dThetaX ) , xAxis ) ;
63
70
64
- vec3 . transformMat4 ( sliceNormal , this . _state . sliceNormal , planeMat ) ;
65
- vec3 . transformMat4 ( sliceViewUp , this . _state . viewUp , planeMat ) ;
71
+ vec3 . transformMat4 ( nSliceNormal , sliceNormal , planeMat ) ;
72
+ vec3 . transformMat4 ( nViewUp , viewUp , planeMat ) ;
73
+
74
+ if ( dThetaZ !== 0 ) {
75
+ // Rotate the viewUp in 90 degree increments
76
+ const zRotQuat = quat . create ( ) ;
77
+ // Use negative degrees clockwise rotation since the axis should really be the direction of projection, which is the negative of the plane normal
78
+ quat . setAxisAngle ( zRotQuat , nSliceNormal , degrees2radians ( - dThetaZ ) ) ;
79
+ quat . normalize ( zRotQuat , zRotQuat ) ;
80
+
81
+ // rotate the ViewUp with the z rotation
82
+ vec3 . transformQuat ( nViewUp , nViewUp , zRotQuat ) ;
83
+ }
66
84
67
- this . _state . sliceNormal = sliceNormal ;
68
- this . _state . viewUp = sliceViewUp ;
85
+ this . _state . cache . sliceNormal = nSliceNormal ;
86
+ this . _state . cache . viewUp = nViewUp ;
69
87
70
88
var event = new CustomEvent ( EVENTS . VIEWPORT_ROTATED , {
71
89
detail : {
72
- sliceNormal,
73
- sliceViewUp,
90
+ sliceNormal : nSliceNormal ,
91
+ sliceViewUp : nViewUp ,
74
92
dThetaX,
75
93
dThetaY,
94
+ dThetaZ,
76
95
} ,
77
96
bubbles : true ,
78
97
cancelable : true ,
@@ -81,9 +100,30 @@ export default class {
81
100
this . eventWindow . dispatchEvent ( event ) ;
82
101
} ;
83
102
103
+ rotateAbsolute = ( dThetaX , dThetaY , dThetaZ = 0 ) => {
104
+ this . _rotate (
105
+ this . _state . viewUp ,
106
+ this . _state . sliceNormal ,
107
+ dThetaX ,
108
+ dThetaY ,
109
+ dThetaZ
110
+ ) ;
111
+ } ;
112
+ rotateRelative = ( dThetaX , dThetaY , dThetaZ = 0 ) => {
113
+ this . _rotate (
114
+ this . _state . cache . viewUp ,
115
+ this . _state . cache . sliceNormal ,
116
+ dThetaX ,
117
+ dThetaY ,
118
+ dThetaZ
119
+ ) ;
120
+ } ;
121
+
84
122
setOrientation = ( sliceNormal , viewUp = [ 0 , 1 , 0 ] ) => {
85
- this . _state . sliceNormal = sliceNormal ;
86
- this . _state . viewUp = viewUp ;
123
+ this . _state . sliceNormal = [ ...sliceNormal ] ;
124
+ this . _state . viewUp = [ ...viewUp ] ;
125
+ this . _state . cache . sliceNormal = [ ...sliceNormal ] ;
126
+ this . _state . cache . viewUp = [ ...viewUp ] ;
87
127
} ;
88
128
89
129
getViewUp = ( ) => {
@@ -94,6 +134,14 @@ export default class {
94
134
return this . _state . sliceNormal ;
95
135
} ;
96
136
137
+ getCurrentViewUp = ( ) => {
138
+ return this . _state . cache . viewUp ;
139
+ } ;
140
+
141
+ getCurrentSliceNormal = ( ) => {
142
+ return this . _state . cache . sliceNormal ;
143
+ } ;
144
+
97
145
getReadOnlyViewPort = ( ) => {
98
146
const readOnlyState = JSON . parse ( JSON . stringify ( this . _state ) ) ;
99
147
0 commit comments