Skip to content

Commit

Permalink
add set camera position api (#1975)
Browse files Browse the repository at this point in the history
* add set camera position api

* fix test

---------

Co-authored-by: unknown <yy923683900>
  • Loading branch information
yy923683900 committed May 27, 2023
1 parent e358799 commit 45b487b
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 1 deletion.
157 changes: 156 additions & 1 deletion src/map/Map.Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Point from '../geo/Point';
import Coordinate from '../geo/Coordinate';
import * as mat4 from '../core/util/mat4';
import { subtract, add, scale, normalize, dot, set, distance } from '../core/util/vec3';
import { clamp, interpolate, isNumber, isNil, wrap } from '../core/util';
import { clamp, interpolate, isNumber, isNil, wrap, toDegree, toRadian } from '../core/util';
import { applyMatrix, matrixToQuaternion, quaternionToMatrix, lookAt, setPosition } from '../core/util/math';
import Browser from '../core/Browser';

Expand Down Expand Up @@ -206,6 +206,149 @@ Map.include(/** @lends Map.prototype */{
return this;
},

/**
* set camera movements
* @param {Array} frameOptions
* [{ center: [114, 32], zoom: 14, pitch: 45, bearing: 90, timestamp: 0 }]
* @param {Object} extraOptions
* { autoRotate: true }
*/
setCameraMovements(frameOptions, extraOptions) {
if (!Array.isArray(frameOptions) || !frameOptions.length) {
return this;
}
this.setView({
center: frameOptions[0].center,
zoom: frameOptions[0].zoom,
pitch: frameOptions[0].pitch,
bearing: frameOptions[0].bearing
});
if (frameOptions.length === 1) return this;
let index = 1;
let onFrame = frame => {
if (frame.state.playState === 'finished') {
index++;
if (index === frameOptions.length - 1) onFrame = null;
const frameOption = frameOptions[index];
frameOption.duration = frameOption.timestamp - frameOptions[index - 1].timestamp;
if (extraOptions && extraOptions.autoRotate) {
frameOption.bearing = calculateBearing(frameOptions[index - 1].center, frameOption.center);
}
this._setCameraMovement(frameOption, onFrame);
}
};
if (frameOptions.length === 2) onFrame = null;
const currentBearing = this.getBearing();
this._setCameraMovement({
bearing: currentBearing,
...frameOptions[index],
duration: frameOptions[index].timestamp - frameOptions[index - 1].timestamp
}, onFrame);
const play = () => {
this._animPlayer.play();
};
const pause = () => {
this._animPlayer.pause();
};
const cancel = () => {
this._animPlayer.cancel();
};
const finish = () => {
this._animPlayer.finish();
};
const reverse = () => {
this._animPlayer.reverse();
};
return {
play,
pause,
cancel,
finish,
reverse
};
},

_setCameraMovement(frameOption, frame) {
this.animateTo({
zoom : frameOption.zoom,
center : frameOption.center,
pitch : frameOption.pitch,
bearing : frameOption.bearing
}, {
duration : frameOption.duration,
easing : 'out'
}, frame);
},

/**
* Set camera position
* @param {Object} params
* @property {Array} position
* @property {Number} pitch
* @property {Number} bearing
*/
setCameraPosition(params) {
const { position, pitch, bearing } = params;

const cameraAltitude = position[2] * this._meterToGLPoint;

const centerAltitude = this.centerAltitude || 0;
const centerPointZ = centerAltitude * this._meterToGLPoint;

const cz = cameraAltitude - centerPointZ;

const pitchRadian = pitch * RADIAN;

const cameraToGroundDistance = cz / Math.cos(pitchRadian);

const dist = Math.sin(pitchRadian) * cameraToGroundDistance;

const cameraToCenterDistance = cameraToGroundDistance + centerPointZ;

const zoom = this._getZoomFromCameraToCenterDistance(cameraToCenterDistance);

const wrapBearing = wrap(bearing, -180, 180);
const bearingRadian = wrapBearing * RADIAN;

const glRes = this.getGLRes();
const tempCoord = new Coordinate(position[0], position[1]);
const tempPoint = this.coordToPointAtRes(tempCoord, glRes);
const point = new Point(0, 0);
point.x = tempPoint.x + dist * Math.sin(bearingRadian);
point.y = tempPoint.y + dist * Math.cos(bearingRadian);

const prjCenter = this._pointToPrjAtRes(point, this.getGLRes());
this._setPrjCenter(prjCenter);

this.setView({
bearing,
pitch,
zoom
});

return this;
},

_getZoomFromCameraToCenterDistance(distance) {
const ratio = this._getFovRatio();
const scale = distance * ratio * 2 / (this.height || 1) * this.getGLRes();
const resolutions = this._getResolutions();
let z = 0;
for (z; z < resolutions.length - 1; z++) {
if (resolutions[z] === scale) {
return z;
} else if (resolutions[z + 1] === scale) {
return z + 1;
} else if (scale < resolutions[z] && scale > resolutions[z + 1]) {
z = (scale - resolutions[z]) / (resolutions[z + 1] - resolutions[z]) + z;
return z - 1;
} else {
continue;
}
}
return z;
},

/**
* Whether the map is rotating or tilting.
* @return {Boolean}
Expand Down Expand Up @@ -754,3 +897,15 @@ Map.include(/** @lends Map.prototype */{
function createMat4() {
return mat4.identity(new Array(16));
}

function calculateBearing(start, end) {
const lon1 = toRadian(start[0]);
const lon2 = toRadian(end[0]);
const lat1 = toRadian(start[1]);
const lat2 = toRadian(end[1]);
const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
const b =
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
return toDegree(Math.atan2(a, b));
}
80 changes: 80 additions & 0 deletions test/map/MapCameraSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,86 @@ describe('Map.Camera', function () {
});
});

describe('Set camera position', function () {
it('pitch 0, bearing 0', function () {
map.setCameraPosition({
position: [0, 0, 10000],
pitch: 0,
bearing: 0,
})
expect(map.getCenter().x).to.be.eql(0);
expect(map.getCenter().y).to.be.eql(0);
expect(map.getPitch()).to.be.eql(0);
expect(map.getBearing()).to.be.eql(0);
expect(map.getZoom()).to.be.within(8, 9);
});

it('pitch 45, bearing 45', function () {
map.setCameraPosition({
position: [0, 0, 10000],
pitch: 45,
bearing: 45,
})
expect(map.getCenter().x).to.be.within(0.07, 0.08);
expect(map.getCenter().y).to.be.within(0.07, 0.08);
expect(map.getPitch()).to.be.eql(45);
expect(map.getBearing()).to.be.eql(45);
expect(map.getZoom()).to.be.within(7, 8);
});

it('pitch 45, bearing 135', function () {
map.setCameraPosition({
position: [0, 0, 10000],
pitch: 45,
bearing: 135,
})
expect(map.getCenter().x).to.be.within(0.07, 0.08);
expect(map.getCenter().y).to.be.within(-0.08, 0.07);
expect(map.getPitch()).to.be.eql(45);
expect(map.getBearing()).to.be.eql(135);
expect(map.getZoom()).to.be.within(7, 8);
});

it('pitch 45, bearing -45', function () {
map.setCameraPosition({
position: [0, 0, 10000],
pitch: 45,
bearing: -45,
})
expect(map.getCenter().x).to.be.within(-0.08, 0.07);
expect(map.getCenter().y).to.be.within(0.07, 0.08);
expect(map.getPitch()).to.be.eql(45);
expect(map.getBearing()).to.be.eql(-45);
expect(map.getZoom()).to.be.within(7, 8);
});

it('pitch 45, bearing -135', function () {
map.setCameraPosition({
position: [0, 0, 10000],
pitch: 45,
bearing: -135,
})
expect(map.getCenter().x).to.be.within(-0.08, -0.07);
expect(map.getCenter().y).to.be.within(-0.08, -0.07);
expect(map.getPitch()).to.be.eql(45);
expect(map.getBearing()).to.be.eql(-135);
expect(map.getZoom()).to.be.within(7, 8);
});

it('position z', function () {
map.setCameraPosition({
position: [0, 0, 100],
pitch: 0,
bearing: 0,
})
expect(map.getCenter().x).to.be.eql(0);
expect(map.getCenter().y).to.be.eql(0);
expect(map.getPitch()).to.be.eql(0);
expect(map.getBearing()).to.be.eql(0);
expect(map.getZoom()).to.be.within(14, 15);
})
});

describe('containsPoint when pitching', function () {

it('linestring', function () {
Expand Down

0 comments on commit 45b487b

Please sign in to comment.