Skip to content

Commit 45b487b

Browse files
authored
add set camera position api (#1975)
* add set camera position api * fix test --------- Co-authored-by: unknown <yy923683900>
1 parent e358799 commit 45b487b

File tree

2 files changed

+236
-1
lines changed

2 files changed

+236
-1
lines changed

src/map/Map.Camera.js

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Point from '../geo/Point';
33
import Coordinate from '../geo/Coordinate';
44
import * as mat4 from '../core/util/mat4';
55
import { subtract, add, scale, normalize, dot, set, distance } from '../core/util/vec3';
6-
import { clamp, interpolate, isNumber, isNil, wrap } from '../core/util';
6+
import { clamp, interpolate, isNumber, isNil, wrap, toDegree, toRadian } from '../core/util';
77
import { applyMatrix, matrixToQuaternion, quaternionToMatrix, lookAt, setPosition } from '../core/util/math';
88
import Browser from '../core/Browser';
99

@@ -206,6 +206,149 @@ Map.include(/** @lends Map.prototype */{
206206
return this;
207207
},
208208

209+
/**
210+
* set camera movements
211+
* @param {Array} frameOptions
212+
* [{ center: [114, 32], zoom: 14, pitch: 45, bearing: 90, timestamp: 0 }]
213+
* @param {Object} extraOptions
214+
* { autoRotate: true }
215+
*/
216+
setCameraMovements(frameOptions, extraOptions) {
217+
if (!Array.isArray(frameOptions) || !frameOptions.length) {
218+
return this;
219+
}
220+
this.setView({
221+
center: frameOptions[0].center,
222+
zoom: frameOptions[0].zoom,
223+
pitch: frameOptions[0].pitch,
224+
bearing: frameOptions[0].bearing
225+
});
226+
if (frameOptions.length === 1) return this;
227+
let index = 1;
228+
let onFrame = frame => {
229+
if (frame.state.playState === 'finished') {
230+
index++;
231+
if (index === frameOptions.length - 1) onFrame = null;
232+
const frameOption = frameOptions[index];
233+
frameOption.duration = frameOption.timestamp - frameOptions[index - 1].timestamp;
234+
if (extraOptions && extraOptions.autoRotate) {
235+
frameOption.bearing = calculateBearing(frameOptions[index - 1].center, frameOption.center);
236+
}
237+
this._setCameraMovement(frameOption, onFrame);
238+
}
239+
};
240+
if (frameOptions.length === 2) onFrame = null;
241+
const currentBearing = this.getBearing();
242+
this._setCameraMovement({
243+
bearing: currentBearing,
244+
...frameOptions[index],
245+
duration: frameOptions[index].timestamp - frameOptions[index - 1].timestamp
246+
}, onFrame);
247+
const play = () => {
248+
this._animPlayer.play();
249+
};
250+
const pause = () => {
251+
this._animPlayer.pause();
252+
};
253+
const cancel = () => {
254+
this._animPlayer.cancel();
255+
};
256+
const finish = () => {
257+
this._animPlayer.finish();
258+
};
259+
const reverse = () => {
260+
this._animPlayer.reverse();
261+
};
262+
return {
263+
play,
264+
pause,
265+
cancel,
266+
finish,
267+
reverse
268+
};
269+
},
270+
271+
_setCameraMovement(frameOption, frame) {
272+
this.animateTo({
273+
zoom : frameOption.zoom,
274+
center : frameOption.center,
275+
pitch : frameOption.pitch,
276+
bearing : frameOption.bearing
277+
}, {
278+
duration : frameOption.duration,
279+
easing : 'out'
280+
}, frame);
281+
},
282+
283+
/**
284+
* Set camera position
285+
* @param {Object} params
286+
* @property {Array} position
287+
* @property {Number} pitch
288+
* @property {Number} bearing
289+
*/
290+
setCameraPosition(params) {
291+
const { position, pitch, bearing } = params;
292+
293+
const cameraAltitude = position[2] * this._meterToGLPoint;
294+
295+
const centerAltitude = this.centerAltitude || 0;
296+
const centerPointZ = centerAltitude * this._meterToGLPoint;
297+
298+
const cz = cameraAltitude - centerPointZ;
299+
300+
const pitchRadian = pitch * RADIAN;
301+
302+
const cameraToGroundDistance = cz / Math.cos(pitchRadian);
303+
304+
const dist = Math.sin(pitchRadian) * cameraToGroundDistance;
305+
306+
const cameraToCenterDistance = cameraToGroundDistance + centerPointZ;
307+
308+
const zoom = this._getZoomFromCameraToCenterDistance(cameraToCenterDistance);
309+
310+
const wrapBearing = wrap(bearing, -180, 180);
311+
const bearingRadian = wrapBearing * RADIAN;
312+
313+
const glRes = this.getGLRes();
314+
const tempCoord = new Coordinate(position[0], position[1]);
315+
const tempPoint = this.coordToPointAtRes(tempCoord, glRes);
316+
const point = new Point(0, 0);
317+
point.x = tempPoint.x + dist * Math.sin(bearingRadian);
318+
point.y = tempPoint.y + dist * Math.cos(bearingRadian);
319+
320+
const prjCenter = this._pointToPrjAtRes(point, this.getGLRes());
321+
this._setPrjCenter(prjCenter);
322+
323+
this.setView({
324+
bearing,
325+
pitch,
326+
zoom
327+
});
328+
329+
return this;
330+
},
331+
332+
_getZoomFromCameraToCenterDistance(distance) {
333+
const ratio = this._getFovRatio();
334+
const scale = distance * ratio * 2 / (this.height || 1) * this.getGLRes();
335+
const resolutions = this._getResolutions();
336+
let z = 0;
337+
for (z; z < resolutions.length - 1; z++) {
338+
if (resolutions[z] === scale) {
339+
return z;
340+
} else if (resolutions[z + 1] === scale) {
341+
return z + 1;
342+
} else if (scale < resolutions[z] && scale > resolutions[z + 1]) {
343+
z = (scale - resolutions[z]) / (resolutions[z + 1] - resolutions[z]) + z;
344+
return z - 1;
345+
} else {
346+
continue;
347+
}
348+
}
349+
return z;
350+
},
351+
209352
/**
210353
* Whether the map is rotating or tilting.
211354
* @return {Boolean}
@@ -754,3 +897,15 @@ Map.include(/** @lends Map.prototype */{
754897
function createMat4() {
755898
return mat4.identity(new Array(16));
756899
}
900+
901+
function calculateBearing(start, end) {
902+
const lon1 = toRadian(start[0]);
903+
const lon2 = toRadian(end[0]);
904+
const lat1 = toRadian(start[1]);
905+
const lat2 = toRadian(end[1]);
906+
const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
907+
const b =
908+
Math.cos(lat1) * Math.sin(lat2) -
909+
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
910+
return toDegree(Math.atan2(a, b));
911+
}

test/map/MapCameraSpec.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,86 @@ describe('Map.Camera', function () {
453453
});
454454
});
455455

456+
describe('Set camera position', function () {
457+
it('pitch 0, bearing 0', function () {
458+
map.setCameraPosition({
459+
position: [0, 0, 10000],
460+
pitch: 0,
461+
bearing: 0,
462+
})
463+
expect(map.getCenter().x).to.be.eql(0);
464+
expect(map.getCenter().y).to.be.eql(0);
465+
expect(map.getPitch()).to.be.eql(0);
466+
expect(map.getBearing()).to.be.eql(0);
467+
expect(map.getZoom()).to.be.within(8, 9);
468+
});
469+
470+
it('pitch 45, bearing 45', function () {
471+
map.setCameraPosition({
472+
position: [0, 0, 10000],
473+
pitch: 45,
474+
bearing: 45,
475+
})
476+
expect(map.getCenter().x).to.be.within(0.07, 0.08);
477+
expect(map.getCenter().y).to.be.within(0.07, 0.08);
478+
expect(map.getPitch()).to.be.eql(45);
479+
expect(map.getBearing()).to.be.eql(45);
480+
expect(map.getZoom()).to.be.within(7, 8);
481+
});
482+
483+
it('pitch 45, bearing 135', function () {
484+
map.setCameraPosition({
485+
position: [0, 0, 10000],
486+
pitch: 45,
487+
bearing: 135,
488+
})
489+
expect(map.getCenter().x).to.be.within(0.07, 0.08);
490+
expect(map.getCenter().y).to.be.within(-0.08, 0.07);
491+
expect(map.getPitch()).to.be.eql(45);
492+
expect(map.getBearing()).to.be.eql(135);
493+
expect(map.getZoom()).to.be.within(7, 8);
494+
});
495+
496+
it('pitch 45, bearing -45', function () {
497+
map.setCameraPosition({
498+
position: [0, 0, 10000],
499+
pitch: 45,
500+
bearing: -45,
501+
})
502+
expect(map.getCenter().x).to.be.within(-0.08, 0.07);
503+
expect(map.getCenter().y).to.be.within(0.07, 0.08);
504+
expect(map.getPitch()).to.be.eql(45);
505+
expect(map.getBearing()).to.be.eql(-45);
506+
expect(map.getZoom()).to.be.within(7, 8);
507+
});
508+
509+
it('pitch 45, bearing -135', function () {
510+
map.setCameraPosition({
511+
position: [0, 0, 10000],
512+
pitch: 45,
513+
bearing: -135,
514+
})
515+
expect(map.getCenter().x).to.be.within(-0.08, -0.07);
516+
expect(map.getCenter().y).to.be.within(-0.08, -0.07);
517+
expect(map.getPitch()).to.be.eql(45);
518+
expect(map.getBearing()).to.be.eql(-135);
519+
expect(map.getZoom()).to.be.within(7, 8);
520+
});
521+
522+
it('position z', function () {
523+
map.setCameraPosition({
524+
position: [0, 0, 100],
525+
pitch: 0,
526+
bearing: 0,
527+
})
528+
expect(map.getCenter().x).to.be.eql(0);
529+
expect(map.getCenter().y).to.be.eql(0);
530+
expect(map.getPitch()).to.be.eql(0);
531+
expect(map.getBearing()).to.be.eql(0);
532+
expect(map.getZoom()).to.be.within(14, 15);
533+
})
534+
});
535+
456536
describe('containsPoint when pitching', function () {
457537

458538
it('linestring', function () {

0 commit comments

Comments
 (0)