import {MathConsts} from "awayjs-core/lib/geom/MathConsts"; import {Vector3D} from "awayjs-core/lib/geom/Vector3D"; import {DisplayObject} from "../display/DisplayObject"; import {LookAtController} from "../controllers/LookAtController"; /** * Extended camera used to hover round a specified target object. * * @see away.containers.View */ export class HoverController extends LookAtController { public _iCurrentPanAngle:number = 0; public _iCurrentTiltAngle:number = 90; private _panAngle:number = 0; private _tiltAngle:number = 90; private _distance:number = 1000; private _minPanAngle:number = -Infinity; private _maxPanAngle:number = Infinity; private _minTiltAngle:number = -90; private _maxTiltAngle:number = 90; private _steps:number = 8; private _yFactor:number = 2; private _wrapPanAngle:boolean = false; private _upAxis:Vector3D = new Vector3D(); /** * Fractional step taken each time the hover() method is called. Defaults to 8. * * Affects the speed at which the tiltAngle and panAngle resolve to their targets. * * @see #tiltAngle * @see #panAngle */ public get steps():number { return this._steps; } public set steps(val:number) { val = (val < 1)? 1 : val; if (this._steps == val) return; this._steps = val; this.pNotifyUpdate(); } /** * Rotation of the camera in degrees around the y axis. Defaults to 0. */ public get panAngle():number { return this._panAngle; } public set panAngle(val:number) { val = Math.max(this._minPanAngle, Math.min(this._maxPanAngle, val)); if (this._panAngle == val) return; this._panAngle = val; this.pNotifyUpdate(); } /** * Elevation angle of the camera in degrees. Defaults to 90. */ public get tiltAngle():number { return this._tiltAngle; } public set tiltAngle(val:number) { val = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, val)); if (this._tiltAngle == val) return; this._tiltAngle = val; this.pNotifyUpdate(); } /** * Distance between the camera and the specified target. Defaults to 1000. */ public get distance():number { return this._distance; } public set distance(val:number) { if (this._distance == val) return; this._distance = val; this.pNotifyUpdate(); } /** * Minimum bounds for the panAngle. Defaults to -Infinity. * * @see #panAngle */ public get minPanAngle():number { return this._minPanAngle; } public set minPanAngle(val:number) { if (this._minPanAngle == val) return; this._minPanAngle = val; this.panAngle = Math.max(this._minPanAngle, Math.min(this._maxPanAngle, this._panAngle)); } /** * Maximum bounds for the panAngle. Defaults to Infinity. * * @see #panAngle */ public get maxPanAngle():number { return this._maxPanAngle; } public set maxPanAngle(val:number) { if (this._maxPanAngle == val) return; this._maxPanAngle = val; this.panAngle = Math.max(this._minPanAngle, Math.min(this._maxPanAngle, this._panAngle)); } /** * Minimum bounds for the tiltAngle. Defaults to -90. * * @see #tiltAngle */ public get minTiltAngle():number { return this._minTiltAngle; } public set minTiltAngle(val:number) { if (this._minTiltAngle == val) return; this._minTiltAngle = val; this.tiltAngle = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, this._tiltAngle)); } /** * Maximum bounds for the tiltAngle. Defaults to 90. * * @see #tiltAngle */ public get maxTiltAngle():number { return this._maxTiltAngle; } public set maxTiltAngle(val:number) { if (this._maxTiltAngle == val) return; this._maxTiltAngle = val; this.tiltAngle = Math.max(this._minTiltAngle, Math.min(this._maxTiltAngle, this._tiltAngle)); } /** * Fractional difference in distance between the horizontal camera orientation and vertical camera orientation. Defaults to 2. * * @see #distance */ public get yFactor():number { return this._yFactor; } public set yFactor(val:number) { if (this._yFactor == val) return; this._yFactor = val; this.pNotifyUpdate(); } /** * Defines whether the value of the pan angle wraps when over 360 degrees or under 0 degrees. Defaults to false. */ public get wrapPanAngle():boolean { return this._wrapPanAngle; } public set wrapPanAngle(val:boolean) { if (this._wrapPanAngle == val) return; this._wrapPanAngle = val; this.pNotifyUpdate(); } /** * Creates a new HoverController object. */ constructor(targetObject:DisplayObject = null, lookAtObject:DisplayObject = null, panAngle:number = 0, tiltAngle:number = 90, distance:number = 1000, minTiltAngle:number = -90, maxTiltAngle:number = 90, minPanAngle:number = null, maxPanAngle:number = null, steps:number = 8, yFactor:number = 2, wrapPanAngle:boolean = false) { super(targetObject, lookAtObject); this.distance = distance; this.panAngle = panAngle; this.tiltAngle = tiltAngle; this.minPanAngle = ( minPanAngle != null )? minPanAngle : -Infinity; this.maxPanAngle = ( maxPanAngle != null )? maxPanAngle : Infinity; this.minTiltAngle = minTiltAngle; this.maxTiltAngle = maxTiltAngle; this.steps = steps; this.yFactor = yFactor; this.wrapPanAngle = wrapPanAngle; //values passed in contrustor are applied immediately this._iCurrentPanAngle = this._panAngle; this._iCurrentTiltAngle = this._tiltAngle; } /** * Updates the current tilt angle and pan angle values. * * Values are calculated using the defined tiltAngle, panAngle and steps variables. * * @param interpolate If the update to a target pan- or tiltAngle is interpolated. Default is true. * * @see #tiltAngle * @see #panAngle * @see #steps */ public update(interpolate:boolean = true):void { if (this._tiltAngle != this._iCurrentTiltAngle || this._panAngle != this._iCurrentPanAngle) { this._pControllerDirty = true; if (this._wrapPanAngle) { if (this._panAngle < 0) { this._iCurrentPanAngle += this._panAngle%360 + 360 - this._panAngle; this._panAngle = this._panAngle%360 + 360; } else { this._iCurrentPanAngle += this._panAngle%360 - this._panAngle; this._panAngle = this._panAngle%360; } while (this._panAngle - this._iCurrentPanAngle < -180) this._iCurrentPanAngle -= 360; while (this._panAngle - this._iCurrentPanAngle > 180) this._iCurrentPanAngle += 360; } if (interpolate) { this._iCurrentTiltAngle += (this._tiltAngle - this._iCurrentTiltAngle)/(this.steps + 1); this._iCurrentPanAngle += (this._panAngle - this._iCurrentPanAngle)/(this.steps + 1); } else { this._iCurrentPanAngle = this._panAngle; this._iCurrentTiltAngle = this._tiltAngle; } //snap coords if angle differences are close if ((Math.abs(this.tiltAngle - this._iCurrentTiltAngle) < 0.01) && (Math.abs(this._panAngle - this._iCurrentPanAngle) < 0.01)) { this._iCurrentTiltAngle = this._tiltAngle; this._iCurrentPanAngle = this._panAngle; } } var pos:Vector3D = (this.lookAtObject)? this.lookAtObject.transform.position : (this.lookAtPosition)? this.lookAtPosition : this._pOrigin; this.targetObject.x = pos.x + this.distance*Math.sin(this._iCurrentPanAngle*MathConsts.DEGREES_TO_RADIANS)*Math.cos(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS); this.targetObject.y = pos.y + this.distance*Math.sin(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS)*this.yFactor; this.targetObject.z = pos.z + this.distance*Math.cos(this._iCurrentPanAngle*MathConsts.DEGREES_TO_RADIANS)*Math.cos(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS); this._upAxis.x = -Math.sin(this._iCurrentPanAngle*MathConsts.DEGREES_TO_RADIANS)*Math.sin(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS); this._upAxis.y = Math.cos(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS); this._upAxis.z = -Math.cos(this._iCurrentPanAngle*MathConsts.DEGREES_TO_RADIANS)*Math.sin(this._iCurrentTiltAngle*MathConsts.DEGREES_TO_RADIANS); if (this._pTargetObject) { if (this._pLookAtPosition) this._pTargetObject.lookAt(this._pLookAtPosition, this._upAxis); else if (this._pLookAtObject) this._pTargetObject.lookAt(this._pLookAtObject.scene? this._pLookAtObject.scenePosition : this._pLookAtObject.transform.position, this._upAxis); } } }