mirror of https://gitee.com/cf-fz/WebCAD.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
773 lines
24 KiB
773 lines
24 KiB
8 years ago
|
import * as THREE from 'three';
|
||
|
|
||
|
const STATE = {
|
||
|
NONE: - 1,
|
||
|
ROTATE: 0,
|
||
|
DOLLY: 1,
|
||
|
PAN: 2,
|
||
|
TOUCH_ROTATE: 3,
|
||
|
TOUCH_DOLLY: 4,
|
||
|
TOUCH_PAN: 5
|
||
|
};
|
||
|
|
||
|
const CHANGE_EVENT = { type: 'change' };
|
||
|
const START_EVENT = { type: 'start' };
|
||
|
const END_EVENT = { type: 'end' };
|
||
|
const EPS = 0.000001;
|
||
|
|
||
|
/**
|
||
|
* @author qiao / https://github.com/qiao
|
||
|
* @author mrdoob / http://mrdoob.com
|
||
|
* @author alteredq / http://alteredqualia.com/
|
||
|
* @author WestLangley / http://github.com/WestLangley
|
||
|
* @author erich666 / http://erichaines.com
|
||
|
* @author nicolaspanel / http://github.com/nicolaspanel
|
||
|
*
|
||
|
* This set of controls performs orbiting, dollying (zooming), and panning.
|
||
|
* Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
|
||
|
* Orbit - left mouse / touch: one finger move
|
||
|
* Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
|
||
|
* Pan - right mouse, or arrow keys / touch: three finger swipe
|
||
|
*/
|
||
7 years ago
|
export class OrbitControls extends THREE.EventDispatcher
|
||
|
{
|
||
8 years ago
|
public m_Camera: THREE.Camera;
|
||
8 years ago
|
domElement: HTMLElement | HTMLDocument;
|
||
|
window: Window;
|
||
|
// API
|
||
|
enabled: boolean;
|
||
|
target: THREE.Vector3;
|
||
|
enableZoom: boolean;
|
||
|
zoomSpeed: number;
|
||
|
minDistance: number;
|
||
|
maxDistance: number;
|
||
|
enableRotate: boolean;
|
||
|
rotateSpeed: number;
|
||
|
enablePan: boolean;
|
||
|
keyPanSpeed: number;
|
||
|
autoRotate: boolean;
|
||
|
autoRotateSpeed: number;
|
||
|
minZoom: number;
|
||
|
maxZoom: number;
|
||
|
minPolarAngle: number;
|
||
|
maxPolarAngle: number;
|
||
|
minAzimuthAngle: number;
|
||
|
maxAzimuthAngle: number;
|
||
|
enableKeys: boolean;
|
||
7 years ago
|
keys: { LEFT: number; UP: number; RIGHT: number; BOTTOM: number; CTRL: number };
|
||
8 years ago
|
mouseButtons: { ORBIT: THREE.MOUSE; ZOOM: THREE.MOUSE; PAN: THREE.MOUSE; };
|
||
|
enableDamping: boolean;
|
||
|
dampingFactor: number;
|
||
7 years ago
|
//Ctrl 按下
|
||
|
m_bCtrlIsDown: boolean;
|
||
8 years ago
|
|
||
|
private spherical: THREE.Spherical;
|
||
|
private sphericalDelta: THREE.Spherical;
|
||
|
private scale: number;
|
||
|
private target0: THREE.Vector3;
|
||
|
private position0: THREE.Vector3;
|
||
|
private zoom0: any;
|
||
|
private state: number;
|
||
|
private panOffset: THREE.Vector3;
|
||
|
private zoomChanged: boolean;
|
||
|
|
||
|
private rotateStart: THREE.Vector2;
|
||
|
private rotateEnd: THREE.Vector2;
|
||
|
private rotateDelta: THREE.Vector2
|
||
|
|
||
|
private panStart: THREE.Vector2;
|
||
|
private panEnd: THREE.Vector2;
|
||
|
private panDelta: THREE.Vector2;
|
||
|
|
||
|
private dollyStart: THREE.Vector2;
|
||
|
private dollyEnd: THREE.Vector2;
|
||
|
private dollyDelta: THREE.Vector2;
|
||
|
|
||
|
private updateLastPosition: THREE.Vector3;
|
||
|
private updateOffset: THREE.Vector3;
|
||
|
private updateQuat: THREE.Quaternion;
|
||
|
private updateLastQuaternion: THREE.Quaternion;
|
||
|
private updateQuatInverse: THREE.Quaternion;
|
||
|
|
||
|
private panLeftV: THREE.Vector3;
|
||
|
private panUpV: THREE.Vector3;
|
||
|
private panInternalOffset: THREE.Vector3;
|
||
|
|
||
|
private onContextMenu: EventListener;
|
||
|
private onMouseUp: EventListener;
|
||
|
private onMouseDown: EventListener;
|
||
|
private onMouseMove: EventListener;
|
||
|
private onMouseWheel: EventListener;
|
||
|
private onTouchStart: EventListener;
|
||
|
private onTouchEnd: EventListener;
|
||
|
private onTouchMove: EventListener;
|
||
|
private onKeyDown: EventListener;
|
||
|
|
||
7 years ago
|
constructor(camera: THREE.Camera, domElement?: HTMLElement, domWindow?: Window)
|
||
|
{
|
||
8 years ago
|
super();
|
||
8 years ago
|
this.m_Camera = camera;
|
||
8 years ago
|
|
||
|
this.domElement = (domElement !== undefined) ? domElement : document;
|
||
|
this.window = (domWindow !== undefined) ? domWindow : window;
|
||
|
|
||
|
// Set to false to disable this control
|
||
|
this.enabled = true;
|
||
|
|
||
|
// "target" sets the location of focus, where the object orbits around
|
||
|
this.target = new THREE.Vector3();
|
||
|
|
||
|
// How far you can dolly in and out ( PerspectiveCamera only )
|
||
|
this.minDistance = 0;
|
||
|
this.maxDistance = Infinity;
|
||
|
|
||
|
// How far you can zoom in and out ( OrthographicCamera only )
|
||
|
this.minZoom = 0;
|
||
|
this.maxZoom = Infinity;
|
||
|
|
||
|
// How far you can orbit vertically, upper and lower limits.
|
||
|
// Range is 0 to Math.PI radians.
|
||
7 years ago
|
this.minPolarAngle = 0; // radians 0
|
||
8 years ago
|
this.maxPolarAngle = Math.PI; // radians
|
||
|
|
||
|
// How far you can orbit horizontally, upper and lower limits.
|
||
|
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
|
||
|
this.minAzimuthAngle = - Infinity; // radians
|
||
|
this.maxAzimuthAngle = Infinity; // radians
|
||
|
|
||
|
// Set to true to enable damping (inertia)
|
||
|
// If damping is enabled, you must call controls.update() in your animation loop
|
||
|
this.enableDamping = false;
|
||
|
this.dampingFactor = 0.25;
|
||
|
|
||
|
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
|
||
|
// Set to false to disable zooming
|
||
|
this.enableZoom = true;
|
||
|
this.zoomSpeed = 1.0;
|
||
|
|
||
|
// Set to false to disable rotating
|
||
|
this.enableRotate = true;
|
||
|
this.rotateSpeed = 1.0;
|
||
|
|
||
|
// Set to false to disable panning
|
||
|
this.enablePan = true;
|
||
|
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
|
||
|
|
||
|
// Set to true to automatically rotate around the target
|
||
|
// If auto-rotate is enabled, you must call controls.update() in your animation loop
|
||
|
this.autoRotate = false;
|
||
|
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
|
||
|
|
||
|
// Set to false to disable use of the keys
|
||
|
this.enableKeys = true;
|
||
|
|
||
|
// The four arrow keys
|
||
7 years ago
|
this.keys = { CTRL: 17, LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
|
||
8 years ago
|
|
||
|
// Mouse buttons
|
||
7 years ago
|
this.mouseButtons = { ORBIT: THREE.MOUSE.MIDDLE, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.MIDDLE };
|
||
8 years ago
|
|
||
|
// for reset
|
||
|
this.target0 = this.target.clone();
|
||
8 years ago
|
this.position0 = this.m_Camera.position.clone();
|
||
|
this.zoom0 = (this.m_Camera as any).zoom;
|
||
8 years ago
|
|
||
|
// for update speedup
|
||
|
this.updateOffset = new THREE.Vector3();
|
||
|
// so camera.up is the orbit axis
|
||
8 years ago
|
this.updateQuat = new THREE.Quaternion().setFromUnitVectors(camera.up, new THREE.Vector3(0, 1, 0));
|
||
8 years ago
|
this.updateQuatInverse = this.updateQuat.clone().inverse();
|
||
|
this.updateLastPosition = new THREE.Vector3();
|
||
|
this.updateLastQuaternion = new THREE.Quaternion();
|
||
|
|
||
|
this.state = STATE.NONE;
|
||
|
this.scale = 1;
|
||
|
|
||
|
// current position in spherical coordinates
|
||
|
this.spherical = new THREE.Spherical();
|
||
|
this.sphericalDelta = new THREE.Spherical();
|
||
|
|
||
|
this.panOffset = new THREE.Vector3();
|
||
|
this.zoomChanged = false;
|
||
|
|
||
|
this.rotateStart = new THREE.Vector2();
|
||
|
this.rotateEnd = new THREE.Vector2();
|
||
|
this.rotateDelta = new THREE.Vector2();
|
||
|
|
||
|
this.panStart = new THREE.Vector2();
|
||
|
this.panEnd = new THREE.Vector2();
|
||
|
this.panDelta = new THREE.Vector2();
|
||
|
|
||
|
this.dollyStart = new THREE.Vector2();
|
||
|
this.dollyEnd = new THREE.Vector2();
|
||
|
this.dollyDelta = new THREE.Vector2();
|
||
|
|
||
|
this.panLeftV = new THREE.Vector3();
|
||
|
this.panUpV = new THREE.Vector3();
|
||
|
this.panInternalOffset = new THREE.Vector3();
|
||
|
|
||
|
// event handlers - FSM: listen for events and reset state
|
||
|
|
||
7 years ago
|
// http://www.itwendao.com/article/detail/288536.html
|
||
|
this.onMouseDown = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
if (this.enabled === false) return;
|
||
|
event.preventDefault();
|
||
7 years ago
|
if ((event as any).button === this.mouseButtons.ORBIT)
|
||
|
{
|
||
|
//旋转
|
||
|
if (this.m_bCtrlIsDown)
|
||
|
{
|
||
|
if (this.enableRotate === false) return;
|
||
|
this.rotateStart.set(event.clientX, event.clientY);
|
||
|
this.state = STATE.ROTATE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (this.enablePan === false) return;
|
||
|
this.panStart.set(event.clientX, event.clientY);
|
||
|
this.state = STATE.PAN;
|
||
|
}
|
||
8 years ago
|
}
|
||
7 years ago
|
// //旋转
|
||
|
// if ((event as any).button === this.mouseButtons.ORBIT)
|
||
|
// {
|
||
|
// if (this.enableRotate === false) return;
|
||
|
// this.rotateStart.set(event.clientX, event.clientY);
|
||
|
// this.state = STATE.ROTATE;
|
||
|
// }
|
||
|
// //缩放
|
||
|
// else if (event.button === this.mouseButtons.ZOOM)
|
||
|
// {
|
||
|
// if (this.enableZoom === false) return;
|
||
|
// this.dollyStart.set(event.clientX, event.clientY);
|
||
|
// this.state = STATE.DOLLY;
|
||
|
// }
|
||
|
// //平移
|
||
|
// else if (event.button === this.mouseButtons.PAN)
|
||
|
// {
|
||
|
// if (this.enablePan === false) return;
|
||
|
// this.panStart.set(event.clientX, event.clientY);
|
||
|
// this.state = STATE.PAN;
|
||
|
// }
|
||
|
|
||
|
if (this.state !== STATE.NONE)
|
||
|
{
|
||
8 years ago
|
document.addEventListener('mousemove', this.onMouseMove, false);
|
||
|
document.addEventListener('mouseup', this.onMouseUp, false);
|
||
|
this.dispatchEvent(START_EVENT);
|
||
|
}
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onMouseMove = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false) return;
|
||
|
|
||
|
event.preventDefault();
|
||
|
|
||
7 years ago
|
if (this.state === STATE.ROTATE)
|
||
|
{
|
||
8 years ago
|
if (this.enableRotate === false) return;
|
||
|
this.rotateEnd.set(event.clientX, event.clientY);
|
||
|
this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart);
|
||
|
const element = this.domElement === document ? this.domElement.body : this.domElement;
|
||
|
|
||
|
// rotating across whole screen goes 360 degrees around
|
||
|
this.rotateLeft(2 * Math.PI * this.rotateDelta.x / (element as any).clientWidth * this.rotateSpeed);
|
||
|
// rotating up and down along whole screen attempts to go 360, but limited to 180
|
||
|
this.rotateUp(2 * Math.PI * this.rotateDelta.y / (element as any).clientHeight * this.rotateSpeed);
|
||
|
this.rotateStart.copy(this.rotateEnd);
|
||
|
|
||
|
this.update();
|
||
7 years ago
|
} else if (this.state === STATE.DOLLY)
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enableZoom === false) return;
|
||
|
|
||
|
this.dollyEnd.set(event.clientX, event.clientY);
|
||
|
this.dollyDelta.subVectors(this.dollyEnd, this.dollyStart);
|
||
|
|
||
7 years ago
|
if (this.dollyDelta.y > 0)
|
||
|
{
|
||
8 years ago
|
this.dollyIn(this.getZoomScale());
|
||
7 years ago
|
} else if (this.dollyDelta.y < 0)
|
||
|
{
|
||
8 years ago
|
this.dollyOut(this.getZoomScale());
|
||
|
}
|
||
|
|
||
|
this.dollyStart.copy(this.dollyEnd);
|
||
|
this.update();
|
||
7 years ago
|
} else if (this.state === STATE.PAN)
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enablePan === false) return;
|
||
|
|
||
|
this.panEnd.set(event.clientX, event.clientY);
|
||
|
this.panDelta.subVectors(this.panEnd, this.panStart);
|
||
|
this.pan(this.panDelta.x, this.panDelta.y);
|
||
|
this.panStart.copy(this.panEnd);
|
||
|
this.update();
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
this.onMouseUp = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
if (this.enabled === false) return;
|
||
|
document.removeEventListener('mousemove', this.onMouseMove, false);
|
||
|
document.removeEventListener('mouseup', this.onMouseUp, false);
|
||
|
|
||
|
this.dispatchEvent(END_EVENT);
|
||
|
this.state = STATE.NONE;
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onMouseWheel = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false || this.enableZoom === false || (this.state !== STATE.NONE && this.state !== STATE.ROTATE)) return;
|
||
|
|
||
|
event.preventDefault();
|
||
|
event.stopPropagation();
|
||
|
|
||
7 years ago
|
if (event.deltaY < 0)
|
||
|
{
|
||
8 years ago
|
this.dollyOut(this.getZoomScale());
|
||
7 years ago
|
} else if (event.deltaY > 0)
|
||
|
{
|
||
8 years ago
|
this.dollyIn(this.getZoomScale());
|
||
|
}
|
||
|
|
||
|
this.update();
|
||
|
|
||
|
this.dispatchEvent(START_EVENT); // not sure why these are here...
|
||
|
this.dispatchEvent(END_EVENT);
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onKeyDown = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false || this.enableKeys === false || this.enablePan === false) return;
|
||
|
|
||
7 years ago
|
switch (event.keyCode)
|
||
|
{
|
||
8 years ago
|
case this.keys.UP: {
|
||
|
this.pan(0, this.keyPanSpeed);
|
||
|
this.update();
|
||
|
} break;
|
||
|
case this.keys.BOTTOM: {
|
||
|
this.pan(0, - this.keyPanSpeed);
|
||
|
this.update();
|
||
|
} break;
|
||
|
case this.keys.LEFT: {
|
||
|
this.pan(this.keyPanSpeed, 0);
|
||
|
this.update();
|
||
|
} break;
|
||
|
case this.keys.RIGHT: {
|
||
|
this.pan(- this.keyPanSpeed, 0);
|
||
|
this.update();
|
||
|
} break;
|
||
7 years ago
|
case this.keys.CTRL: {
|
||
|
this.m_bCtrlIsDown = true;
|
||
|
}
|
||
8 years ago
|
}
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onTouchStart = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false) return;
|
||
|
|
||
7 years ago
|
switch (event.touches.length)
|
||
|
{
|
||
8 years ago
|
// one-fingered touch: rotate
|
||
|
case 1: {
|
||
|
if (this.enableRotate === false) return;
|
||
|
|
||
|
this.rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
|
||
|
this.state = STATE.TOUCH_ROTATE;
|
||
|
} break;
|
||
|
// two-fingered touch: dolly
|
||
|
case 2: {
|
||
|
if (this.enableZoom === false) return;
|
||
|
|
||
|
var dx = event.touches[0].pageX - event.touches[1].pageX;
|
||
|
var dy = event.touches[0].pageY - event.touches[1].pageY;
|
||
|
|
||
|
var distance = Math.sqrt(dx * dx + dy * dy);
|
||
|
this.dollyStart.set(0, distance);
|
||
|
this.state = STATE.TOUCH_DOLLY;
|
||
|
} break;
|
||
|
// three-fingered touch: pan
|
||
|
case 3: {
|
||
|
if (this.enablePan === false) return;
|
||
|
|
||
|
this.panStart.set(event.touches[0].pageX, event.touches[0].pageY);
|
||
|
this.state = STATE.TOUCH_PAN;
|
||
|
} break;
|
||
|
default: {
|
||
|
this.state = STATE.NONE;
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
if (this.state !== STATE.NONE)
|
||
|
{
|
||
8 years ago
|
this.dispatchEvent(START_EVENT);
|
||
|
}
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onTouchMove = (event: ThreeEvent) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false) return;
|
||
|
event.preventDefault();
|
||
|
event.stopPropagation();
|
||
|
|
||
7 years ago
|
switch (event.touches.length)
|
||
|
{
|
||
8 years ago
|
// one-fingered touch: rotate
|
||
|
case 1: {
|
||
|
if (this.enableRotate === false) return;
|
||
|
if (this.state !== STATE.TOUCH_ROTATE) return; // is this needed?...
|
||
|
|
||
|
this.rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
|
||
|
this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart);
|
||
|
|
||
|
var element = this.domElement === document ? this.domElement.body : this.domElement;
|
||
|
|
||
|
// rotating across whole screen goes 360 degrees around
|
||
|
this.rotateLeft(2 * Math.PI * this.rotateDelta.x / (element as any).clientWidth * this.rotateSpeed);
|
||
|
|
||
|
// rotating up and down along whole screen attempts to go 360, but limited to 180
|
||
|
this.rotateUp(2 * Math.PI * this.rotateDelta.y / (element as any).clientHeight * this.rotateSpeed);
|
||
|
|
||
|
this.rotateStart.copy(this.rotateEnd);
|
||
|
|
||
|
this.update();
|
||
|
} break;
|
||
|
// two-fingered touch: dolly
|
||
|
case 2: {
|
||
|
if (this.enableZoom === false) return;
|
||
|
if (this.state !== STATE.TOUCH_DOLLY) return; // is this needed?...
|
||
|
|
||
|
//console.log( 'handleTouchMoveDolly' );
|
||
|
var dx = event.touches[0].pageX - event.touches[1].pageX;
|
||
|
var dy = event.touches[0].pageY - event.touches[1].pageY;
|
||
|
|
||
|
var distance = Math.sqrt(dx * dx + dy * dy);
|
||
|
|
||
|
this.dollyEnd.set(0, distance);
|
||
|
|
||
|
this.dollyDelta.subVectors(this.dollyEnd, this.dollyStart);
|
||
|
|
||
7 years ago
|
if (this.dollyDelta.y > 0)
|
||
|
{
|
||
8 years ago
|
this.dollyOut(this.getZoomScale());
|
||
7 years ago
|
} else if (this.dollyDelta.y < 0)
|
||
|
{
|
||
8 years ago
|
this.dollyIn(this.getZoomScale());
|
||
|
}
|
||
|
|
||
|
this.dollyStart.copy(this.dollyEnd);
|
||
|
this.update();
|
||
|
} break;
|
||
|
// three-fingered touch: pan
|
||
|
case 3: {
|
||
|
if (this.enablePan === false) return;
|
||
|
if (this.state !== STATE.TOUCH_PAN) return; // is this needed?...
|
||
|
this.panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
|
||
|
this.panDelta.subVectors(this.panEnd, this.panStart);
|
||
|
this.pan(this.panDelta.x, this.panDelta.y);
|
||
|
this.panStart.copy(this.panEnd);
|
||
|
this.update();
|
||
|
} break;
|
||
|
default: {
|
||
|
this.state = STATE.NONE;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
7 years ago
|
this.onTouchEnd = (event: Event) =>
|
||
|
{
|
||
8 years ago
|
|
||
|
if (this.enabled === false) return;
|
||
|
this.dispatchEvent(END_EVENT);
|
||
|
this.state = STATE.NONE;
|
||
|
}
|
||
|
|
||
7 years ago
|
this.onContextMenu = (event) =>
|
||
|
{
|
||
8 years ago
|
event.preventDefault();
|
||
|
};
|
||
|
|
||
|
this.domElement.addEventListener('contextmenu', this.onContextMenu, false);
|
||
|
|
||
|
this.domElement.addEventListener('mousedown', this.onMouseDown, false);
|
||
|
this.domElement.addEventListener('wheel', this.onMouseWheel, false);
|
||
|
|
||
|
this.domElement.addEventListener('touchstart', this.onTouchStart, false);
|
||
|
this.domElement.addEventListener('touchend', this.onTouchEnd, false);
|
||
|
this.domElement.addEventListener('touchmove', this.onTouchMove, false);
|
||
|
|
||
|
this.window.addEventListener('keydown', this.onKeyDown, false);
|
||
7 years ago
|
this.window.addEventListener('keyup', this.onKeyUp, false);
|
||
8 years ago
|
|
||
|
// force an update at start
|
||
|
this.update();
|
||
|
}
|
||
7 years ago
|
onKeyUp = (event: ThreeEvent) =>
|
||
|
{
|
||
|
switch (event.keyCode)
|
||
|
{
|
||
|
case this.keys.CTRL: {
|
||
|
this.m_bCtrlIsDown = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
update()
|
||
|
{
|
||
8 years ago
|
const position = this.m_Camera.position;
|
||
8 years ago
|
this.updateOffset.copy(position).sub(this.target);
|
||
|
|
||
|
// rotate offset to "y-axis-is-up" space
|
||
|
this.updateOffset.applyQuaternion(this.updateQuat);
|
||
|
|
||
|
// angle from z-axis around y-axis
|
||
|
this.spherical.setFromVector3(this.updateOffset);
|
||
|
|
||
7 years ago
|
if (this.autoRotate && this.state === STATE.NONE)
|
||
|
{
|
||
8 years ago
|
this.rotateLeft(this.getAutoRotationAngle());
|
||
|
}
|
||
|
|
||
|
(this.spherical as any).theta += (this.sphericalDelta as any).theta;
|
||
|
(this.spherical as any).phi += (this.sphericalDelta as any).phi;
|
||
7 years ago
|
console.log(this.spherical.phi);
|
||
8 years ago
|
|
||
|
// restrict theta to be between desired limits
|
||
7 years ago
|
// (this.spherical as (any) as any).theta = Math.max(this.minAzimuthAngle, Math.min(this.maxAzimuthAngle, (this.spherical as any).theta));
|
||
8 years ago
|
|
||
|
// restrict phi to be between desired limits
|
||
7 years ago
|
// (this.spherical as any).phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, (this.spherical as any).phi));
|
||
|
|
||
8 years ago
|
|
||
|
this.spherical.makeSafe();
|
||
|
|
||
|
(this.spherical as any).radius *= this.scale;
|
||
|
|
||
|
// restrict radius to be between desired limits
|
||
|
(this.spherical as any).radius = Math.max(this.minDistance, Math.min(this.maxDistance, (this.spherical as any).radius));
|
||
|
|
||
|
// move target to panned location
|
||
|
this.target.add(this.panOffset);
|
||
|
|
||
|
this.updateOffset.setFromSpherical(this.spherical);
|
||
|
|
||
|
// rotate offset back to "camera-up-vector-is-up" space
|
||
|
this.updateOffset.applyQuaternion(this.updateQuatInverse);
|
||
|
|
||
|
position.copy(this.target).add(this.updateOffset);
|
||
|
|
||
8 years ago
|
this.m_Camera.lookAt(this.target);
|
||
8 years ago
|
|
||
7 years ago
|
if (this.enableDamping === true)
|
||
|
{
|
||
8 years ago
|
|
||
|
(this.sphericalDelta as any).theta *= (1 - this.dampingFactor);
|
||
|
(this.sphericalDelta as any).phi *= (1 - this.dampingFactor);
|
||
|
|
||
7 years ago
|
} else
|
||
|
{
|
||
8 years ago
|
|
||
|
this.sphericalDelta.set(0, 0, 0);
|
||
|
|
||
|
}
|
||
|
|
||
|
this.scale = 1;
|
||
|
this.panOffset.set(0, 0, 0);
|
||
|
|
||
|
// update condition is:
|
||
|
// min(camera displacement, camera rotation in radians)^2 > EPS
|
||
|
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
|
||
|
|
||
|
if (this.zoomChanged ||
|
||
8 years ago
|
this.updateLastPosition.distanceToSquared(this.m_Camera.position) > EPS ||
|
||
7 years ago
|
8 * (1 - this.updateLastQuaternion.dot(this.m_Camera.quaternion)) > EPS)
|
||
|
{
|
||
8 years ago
|
|
||
|
this.dispatchEvent(CHANGE_EVENT);
|
||
8 years ago
|
this.updateLastPosition.copy(this.m_Camera.position);
|
||
|
this.updateLastQuaternion.copy(this.m_Camera.quaternion);
|
||
8 years ago
|
this.zoomChanged = false;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
7 years ago
|
panLeft(distance: number, objectMatrix)
|
||
|
{
|
||
8 years ago
|
this.panLeftV.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
|
||
|
this.panLeftV.multiplyScalar(- distance);
|
||
|
this.panOffset.add(this.panLeftV);
|
||
|
}
|
||
|
|
||
7 years ago
|
panUp(distance: number, objectMatrix)
|
||
|
{
|
||
8 years ago
|
this.panUpV.setFromMatrixColumn(objectMatrix, 1); // get Y column of objectMatrix
|
||
|
this.panUpV.multiplyScalar(distance);
|
||
|
this.panOffset.add(this.panUpV);
|
||
|
}
|
||
|
|
||
|
// deltaX and deltaY are in pixels; right and down are positive
|
||
7 years ago
|
pan(deltaX: number, deltaY: number)
|
||
|
{
|
||
8 years ago
|
const element = this.domElement === document ? this.domElement.body : this.domElement;
|
||
|
|
||
7 years ago
|
if (this.m_Camera instanceof THREE.PerspectiveCamera)
|
||
|
{
|
||
8 years ago
|
// perspective
|
||
8 years ago
|
const position = this.m_Camera.position;
|
||
8 years ago
|
this.panInternalOffset.copy(position).sub(this.target);
|
||
|
var targetDistance = this.panInternalOffset.length();
|
||
|
|
||
|
// half of the fov is center to top of screen
|
||
8 years ago
|
targetDistance *= Math.tan((this.m_Camera.fov / 2) * Math.PI / 180.0);
|
||
8 years ago
|
|
||
|
// we actually don't use screenWidth, since perspective camera is fixed to screen height
|
||
8 years ago
|
this.panLeft(2 * deltaX * targetDistance / (element as any).clientHeight, this.m_Camera.matrix);
|
||
|
this.panUp(2 * deltaY * targetDistance / (element as any).clientHeight, this.m_Camera.matrix);
|
||
7 years ago
|
} else if (this.m_Camera instanceof THREE.OrthographicCamera)
|
||
|
{
|
||
8 years ago
|
// orthographic
|
||
8 years ago
|
this.panLeft(deltaX * (this.m_Camera.right - this.m_Camera.left) / this.m_Camera.zoom / (element as any).clientWidth, this.m_Camera.matrix);
|
||
|
this.panUp(deltaY * (this.m_Camera.top - this.m_Camera.bottom) / this.m_Camera.zoom / (element as any).clientHeight, this.m_Camera.matrix);
|
||
7 years ago
|
} else
|
||
|
{
|
||
8 years ago
|
// camera neither orthographic nor perspective
|
||
|
console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.');
|
||
|
this.enablePan = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
dollyIn(dollyScale)
|
||
|
{
|
||
|
if (this.m_Camera instanceof THREE.PerspectiveCamera)
|
||
|
{
|
||
8 years ago
|
this.scale /= dollyScale;
|
||
7 years ago
|
} else if (this.m_Camera instanceof THREE.OrthographicCamera)
|
||
|
{
|
||
8 years ago
|
this.m_Camera.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.m_Camera.zoom * dollyScale));
|
||
|
this.m_Camera.updateProjectionMatrix();
|
||
8 years ago
|
this.zoomChanged = true;
|
||
7 years ago
|
} else
|
||
|
{
|
||
8 years ago
|
console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
|
||
|
this.enableZoom = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
dollyOut(dollyScale)
|
||
|
{
|
||
|
if (this.m_Camera instanceof THREE.PerspectiveCamera)
|
||
|
{
|
||
8 years ago
|
this.scale *= dollyScale;
|
||
7 years ago
|
} else if (this.m_Camera instanceof THREE.OrthographicCamera)
|
||
|
{
|
||
8 years ago
|
this.m_Camera.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.m_Camera.zoom / dollyScale));
|
||
|
this.m_Camera.updateProjectionMatrix();
|
||
8 years ago
|
this.zoomChanged = true;
|
||
7 years ago
|
} else
|
||
|
{
|
||
8 years ago
|
console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
|
||
|
this.enableZoom = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
getAutoRotationAngle()
|
||
|
{
|
||
8 years ago
|
return 2 * Math.PI / 60 / 60 * this.autoRotateSpeed;
|
||
|
}
|
||
|
|
||
7 years ago
|
getZoomScale()
|
||
|
{
|
||
8 years ago
|
return Math.pow(0.95, this.zoomSpeed);
|
||
|
}
|
||
|
|
||
7 years ago
|
rotateLeft(angle: number)
|
||
|
{
|
||
8 years ago
|
(this.sphericalDelta as any).theta -= angle;
|
||
|
}
|
||
|
|
||
7 years ago
|
rotateUp(angle: number)
|
||
|
{
|
||
8 years ago
|
(this.sphericalDelta as any).phi -= angle;
|
||
|
}
|
||
|
|
||
7 years ago
|
getPolarAngle(): number
|
||
|
{
|
||
8 years ago
|
return (this.spherical as any).phi;
|
||
|
}
|
||
|
|
||
7 years ago
|
getAzimuthalAngle(): number
|
||
|
{
|
||
8 years ago
|
return (this.spherical as any).theta;
|
||
|
}
|
||
|
|
||
7 years ago
|
dispose(): void
|
||
|
{
|
||
8 years ago
|
this.domElement.removeEventListener('contextmenu', this.onContextMenu, false);
|
||
|
this.domElement.removeEventListener('mousedown', this.onMouseDown, false);
|
||
|
this.domElement.removeEventListener('wheel', this.onMouseWheel, false);
|
||
|
|
||
|
this.domElement.removeEventListener('touchstart', this.onTouchStart, false);
|
||
|
this.domElement.removeEventListener('touchend', this.onTouchEnd, false);
|
||
|
this.domElement.removeEventListener('touchmove', this.onTouchMove, false);
|
||
|
|
||
|
document.removeEventListener('mousemove', this.onMouseMove, false);
|
||
|
document.removeEventListener('mouseup', this.onMouseUp, false);
|
||
|
|
||
|
this.window.removeEventListener('keydown', this.onKeyDown, false);
|
||
|
//this.dispatchEvent( { type: 'dispose' } ); // should this be added here?
|
||
|
}
|
||
|
|
||
7 years ago
|
reset(): void
|
||
|
{
|
||
8 years ago
|
this.target.copy(this.target0);
|
||
8 years ago
|
this.m_Camera.position.copy(this.position0);
|
||
|
(this.m_Camera as any).zoom = this.zoom0;
|
||
8 years ago
|
|
||
8 years ago
|
(this.m_Camera as any).updateProjectionMatrix();
|
||
8 years ago
|
this.dispatchEvent(CHANGE_EVENT);
|
||
|
|
||
|
this.update();
|
||
|
|
||
|
this.state = STATE.NONE;
|
||
|
}
|
||
|
|
||
|
// backward compatibility
|
||
7 years ago
|
get center(): THREE.Vector3
|
||
|
{
|
||
8 years ago
|
console.warn('THREE.OrbitControls: .center has been renamed to .target');
|
||
|
return this.target;
|
||
|
}
|
||
7 years ago
|
get noZoom(): boolean
|
||
|
{
|
||
8 years ago
|
console.warn('THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.');
|
||
|
return !this.enableZoom;
|
||
|
}
|
||
|
|
||
7 years ago
|
set noZoom(value: boolean)
|
||
|
{
|
||
8 years ago
|
console.warn('THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.');
|
||
|
this.enableZoom = !value;
|
||
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
interface ThreeEvent extends Event
|
||
|
{
|
||
8 years ago
|
clientX: number;
|
||
|
clientY: number;
|
||
|
deltaY: number;
|
||
|
button: THREE.MOUSE;
|
||
|
touches: Array<any>;
|
||
|
keyCode: number;
|
||
|
}
|