-
Notifications
You must be signed in to change notification settings - Fork 6
/
cesium-sphere-camera.js
141 lines (123 loc) · 4.27 KB
/
cesium-sphere-camera.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import {
ScreenSpaceEventType,
Math as CesiumMath,
Cartesian3,
Cartesian2,
Ray,
} from "cesium";
const look3DStartPos = new Cartesian2();
const look3DEndPos = new Cartesian2();
const look3DStartRay = new Ray();
const look3DEndRay = new Ray();
const look3DNegativeRot = new Cartesian3();
const look3DTan = new Cartesian3();
export default class CesiumSphereCamera {
/**
* @param {import('cesium').Viewer} viewer
*/
constructor(viewer) {
this.viewer = viewer;
this.dragging_ = false;
this.active_ = false;
this.handleDownEvent_ = this.handleDownEvent.bind(this);
this.handleMoveEvent_ = this.handleMoveEvent.bind(this);
this.handleUpEvent_ = this.handleUpEvent.bind(this);
}
get active() {
return this.active_;
}
set active(active) {
if (active === this.active_) {
return;
}
this.active_ = active;
this.viewer.scene.screenSpaceCameraController.enableInputs = !active;
if (active) {
this.viewer.screenSpaceEventHandler.setInputAction(this.handleDownEvent_, ScreenSpaceEventType.LEFT_DOWN);
this.viewer.screenSpaceEventHandler.setInputAction(this.handleMoveEvent_, ScreenSpaceEventType.MOUSE_MOVE);
this.viewer.screenSpaceEventHandler.setInputAction(this.handleUpEvent_, ScreenSpaceEventType.LEFT_UP);
} else {
this.viewer.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_DOWN);
this.viewer.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE);
this.viewer.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_UP);
}
}
handleDownEvent() {
this.dragging_ = true;
}
/**
* Code from look3D function in ScreenSpaceCameraController
* @param {import('cesium').ScreenSpaceEventHandler.MotionEvent} movement
*/
handleMoveEvent(movement) {
if (!this.dragging_) {
return;
}
const camera = this.viewer.camera;
// x axis
let angle = 0.0;
look3DStartPos.x = movement.startPosition.x;
look3DStartPos.y = 0.0;
look3DEndPos.x = movement.endPosition.x;
look3DEndPos.y = 0.0;
let startDirection = camera.getPickRay(look3DStartPos, look3DStartRay).direction;
let endDirection = camera.getPickRay(look3DEndPos, look3DEndRay).direction;
let dot = Cartesian3.dot(startDirection, endDirection);
if (dot < 1.0) {
// dot is in [0, 1]
angle = Math.acos(dot);
}
angle = movement.startPosition.x > movement.endPosition.x ? -angle : angle;
const rotationAxis =
this.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal(camera.position);
camera.look(rotationAxis, -angle);
// y axis
look3DStartPos.x = 0.0;
look3DStartPos.y = movement.startPosition.y;
look3DEndPos.x = 0.0;
look3DEndPos.y = movement.endPosition.y;
startDirection = camera.getPickRay(look3DStartPos, look3DStartRay).direction;
endDirection = camera.getPickRay(look3DEndPos, look3DEndRay).direction;
angle = 0.0;
dot = Cartesian3.dot(startDirection, endDirection);
if (dot < 1.0) {
// dot is in [0, 1]
angle = Math.acos(dot);
}
angle = movement.startPosition.y > movement.endPosition.y ? -angle : angle;
const direction = camera.direction;
const negativeRotationAxis = Cartesian3.negate(
rotationAxis,
look3DNegativeRot
);
const northParallel = Cartesian3.equalsEpsilon(
direction,
rotationAxis,
CesiumMath.EPSILON2
);
const southParallel = Cartesian3.equalsEpsilon(
direction,
negativeRotationAxis,
CesiumMath.EPSILON2
);
if (!northParallel && !southParallel) {
dot = Cartesian3.dot(direction, rotationAxis);
let angleToAxis = CesiumMath.acosClamped(dot);
if (angle > 0 && angle > angleToAxis) {
angle = angleToAxis - CesiumMath.EPSILON4;
}
dot = Cartesian3.dot(direction, negativeRotationAxis);
angleToAxis = CesiumMath.acosClamped(dot);
if (angle < 0 && -angle > angleToAxis) {
angle = -angleToAxis + CesiumMath.EPSILON4;
}
const tangent = Cartesian3.cross(rotationAxis, direction, look3DTan);
camera.look(tangent, angle);
} else if ((northParallel && angle < 0) || (southParallel && angle > 0)) {
camera.look(camera.right, -angle);
}
}
handleUpEvent() {
this.dragging_ = false;
}
}