1 #include <mbgl/map/map.hpp>
2 #include <mbgl/map/camera.hpp>
3 #include <mbgl/map/transform.hpp>
4 #include <mbgl/map/transform_state.hpp>
5 #include <mbgl/annotation/annotation_manager.hpp>
6 #include <mbgl/style/style_impl.hpp>
7 #include <mbgl/style/observer.hpp>
8 #include <mbgl/renderer/update_parameters.hpp>
9 #include <mbgl/renderer/renderer_frontend.hpp>
10 #include <mbgl/renderer/renderer_observer.hpp>
11 #include <mbgl/storage/file_source.hpp>
12 #include <mbgl/storage/resource.hpp>
13 #include <mbgl/storage/response.hpp>
14 #include <mbgl/util/constants.hpp>
15 #include <mbgl/util/math.hpp>
16 #include <mbgl/util/exception.hpp>
17 #include <mbgl/util/mapbox.hpp>
18 #include <mbgl/util/tile_coordinate.hpp>
19 #include <mbgl/actor/scheduler.hpp>
20 #include <mbgl/util/logging.hpp>
21 #include <mbgl/math/log2.hpp>
22 #include <utility>
23
24 namespace mbgl {
25
26 using namespace style;
27
28 struct StillImageRequest {
StillImageRequestmbgl::StillImageRequest29 StillImageRequest(Map::StillImageCallback&& callback_)
30 : callback(std::move(callback_)) {
31 }
32
33 Map::StillImageCallback callback;
34 };
35
36 class Map::Impl : public style::Observer,
37 public RendererObserver {
38 public:
39 Impl(Map&,
40 RendererFrontend&,
41 MapObserver&,
42 float pixelRatio,
43 FileSource&,
44 Scheduler&,
45 MapMode,
46 ConstrainMode,
47 ViewportMode);
48
49 ~Impl();
50
51 // StyleObserver
52 void onSourceChanged(style::Source&) override;
53 void onUpdate() override;
54 void onStyleLoading() override;
55 void onStyleLoaded() override;
56 void onStyleError(std::exception_ptr) override;
57
58 // RendererObserver
59 void onInvalidate() override;
60 void onResourceError(std::exception_ptr) override;
61 void onWillStartRenderingFrame() override;
62 void onDidFinishRenderingFrame(RenderMode, bool) override;
63 void onWillStartRenderingMap() override;
64 void onDidFinishRenderingMap() override;
65
66 Map& map;
67 MapObserver& observer;
68 RendererFrontend& rendererFrontend;
69 FileSource& fileSource;
70 Scheduler& scheduler;
71
72 Transform transform;
73
74 const MapMode mode;
75 const float pixelRatio;
76
77 MapDebugOptions debugOptions { MapDebugOptions::NoDebug };
78
79 std::unique_ptr<Style> style;
80 AnnotationManager annotationManager;
81
82 bool cameraMutated = false;
83
84 uint8_t prefetchZoomDelta = util::DEFAULT_PREFETCH_ZOOM_DELTA;
85
86 bool loading = false;
87 bool rendererFullyLoaded;
88 std::unique_ptr<StillImageRequest> stillImageRequest;
89 };
90
Map(RendererFrontend & rendererFrontend,MapObserver & mapObserver,const Size size,const float pixelRatio,FileSource & fileSource,Scheduler & scheduler,MapMode mapMode,ConstrainMode constrainMode,ViewportMode viewportMode)91 Map::Map(RendererFrontend& rendererFrontend,
92 MapObserver& mapObserver,
93 const Size size,
94 const float pixelRatio,
95 FileSource& fileSource,
96 Scheduler& scheduler,
97 MapMode mapMode,
98 ConstrainMode constrainMode,
99 ViewportMode viewportMode)
100 : impl(std::make_unique<Impl>(*this,
101 rendererFrontend,
102 mapObserver,
103 pixelRatio,
104 fileSource,
105 scheduler,
106 mapMode,
107 constrainMode,
108 viewportMode)) {
109 impl->transform.resize(size);
110 }
111
Impl(Map & map_,RendererFrontend & frontend,MapObserver & mapObserver,float pixelRatio_,FileSource & fileSource_,Scheduler & scheduler_,MapMode mode_,ConstrainMode constrainMode_,ViewportMode viewportMode_)112 Map::Impl::Impl(Map& map_,
113 RendererFrontend& frontend,
114 MapObserver& mapObserver,
115 float pixelRatio_,
116 FileSource& fileSource_,
117 Scheduler& scheduler_,
118 MapMode mode_,
119 ConstrainMode constrainMode_,
120 ViewportMode viewportMode_)
121 : map(map_),
122 observer(mapObserver),
123 rendererFrontend(frontend),
124 fileSource(fileSource_),
125 scheduler(scheduler_),
126 transform(observer,
127 constrainMode_,
128 viewportMode_),
129 mode(mode_),
130 pixelRatio(pixelRatio_),
131 style(std::make_unique<Style>(scheduler, fileSource, pixelRatio)),
132 annotationManager(*style) {
133
134 style->impl->setObserver(this);
135 rendererFrontend.setObserver(*this);
136 }
137
~Impl()138 Map::Impl::~Impl() {
139 // Explicitly reset the RendererFrontend first to ensure it releases
140 // All shared resources (AnnotationManager)
141 rendererFrontend.reset();
142 };
143
144 Map::~Map() = default;
145
renderStill(StillImageCallback callback)146 void Map::renderStill(StillImageCallback callback) {
147 if (!callback) {
148 Log::Error(Event::General, "StillImageCallback not set");
149 return;
150 }
151
152 if (impl->mode != MapMode::Static && impl->mode != MapMode::Tile) {
153 callback(std::make_exception_ptr(util::MisuseException("Map is not in static or tile image render modes")));
154 return;
155 }
156
157 if (impl->stillImageRequest) {
158 callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")));
159 return;
160 }
161
162 if (impl->style->impl->getLastError()) {
163 callback(impl->style->impl->getLastError());
164 return;
165 }
166
167 impl->stillImageRequest = std::make_unique<StillImageRequest>(std::move(callback));
168
169 impl->onUpdate();
170 }
171
renderStill(const CameraOptions & camera,MapDebugOptions debugOptions,StillImageCallback callback)172 void Map::renderStill(const CameraOptions& camera, MapDebugOptions debugOptions, StillImageCallback callback) {
173 impl->cameraMutated = true;
174 impl->debugOptions = debugOptions;
175 impl->transform.jumpTo(camera);
176 renderStill(std::move(callback));
177 }
178
triggerRepaint()179 void Map::triggerRepaint() {
180 impl->onUpdate();
181 }
182
183 #pragma mark - Map::Impl RendererObserver
184
onWillStartRenderingMap()185 void Map::Impl::onWillStartRenderingMap() {
186 if (mode == MapMode::Continuous) {
187 observer.onWillStartRenderingMap();
188 }
189 }
190
onWillStartRenderingFrame()191 void Map::Impl::onWillStartRenderingFrame() {
192 if (mode == MapMode::Continuous) {
193 observer.onWillStartRenderingFrame();
194 }
195 }
196
onDidFinishRenderingFrame(RenderMode renderMode,bool needsRepaint)197 void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepaint) {
198 rendererFullyLoaded = renderMode == RenderMode::Full;
199
200 if (mode == MapMode::Continuous) {
201 observer.onDidFinishRenderingFrame(MapObserver::RenderMode(renderMode));
202
203 if (needsRepaint || transform.inTransition()) {
204 onUpdate();
205 }
206 } else if (stillImageRequest && rendererFullyLoaded) {
207 auto request = std::move(stillImageRequest);
208 request->callback(nullptr);
209 }
210 }
211
onDidFinishRenderingMap()212 void Map::Impl::onDidFinishRenderingMap() {
213 if (mode == MapMode::Continuous && loading) {
214 observer.onDidFinishRenderingMap(MapObserver::RenderMode::Full);
215 if (loading) {
216 loading = false;
217 observer.onDidFinishLoadingMap();
218 }
219 }
220 };
221
222 #pragma mark - Style
223
getStyle()224 style::Style& Map::getStyle() {
225 return *impl->style;
226 }
227
getStyle() const228 const style::Style& Map::getStyle() const {
229 return *impl->style;
230 }
231
setStyle(std::unique_ptr<Style> style)232 void Map::setStyle(std::unique_ptr<Style> style) {
233 assert(style);
234 impl->onStyleLoading();
235 impl->style = std::move(style);
236 impl->annotationManager.setStyle(*impl->style);
237 }
238
239 #pragma mark - Transitions
240
cancelTransitions()241 void Map::cancelTransitions() {
242 impl->transform.cancelTransitions();
243 impl->onUpdate();
244 }
245
setGestureInProgress(bool inProgress)246 void Map::setGestureInProgress(bool inProgress) {
247 impl->transform.setGestureInProgress(inProgress);
248 impl->onUpdate();
249 }
250
isGestureInProgress() const251 bool Map::isGestureInProgress() const {
252 return impl->transform.isGestureInProgress();
253 }
254
isRotating() const255 bool Map::isRotating() const {
256 return impl->transform.isRotating();
257 }
258
isScaling() const259 bool Map::isScaling() const {
260 return impl->transform.isScaling();
261 }
262
isPanning() const263 bool Map::isPanning() const {
264 return impl->transform.isPanning();
265 }
266
267 #pragma mark -
268
getCameraOptions(const EdgeInsets & padding) const269 CameraOptions Map::getCameraOptions(const EdgeInsets& padding) const {
270 return impl->transform.getCameraOptions(padding);
271 }
272
jumpTo(const CameraOptions & camera)273 void Map::jumpTo(const CameraOptions& camera) {
274 impl->cameraMutated = true;
275 impl->transform.jumpTo(camera);
276 impl->onUpdate();
277 }
278
easeTo(const CameraOptions & camera,const AnimationOptions & animation)279 void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
280 impl->cameraMutated = true;
281 impl->transform.easeTo(camera, animation);
282 impl->onUpdate();
283 }
284
flyTo(const CameraOptions & camera,const AnimationOptions & animation)285 void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
286 impl->cameraMutated = true;
287 impl->transform.flyTo(camera, animation);
288 impl->onUpdate();
289 }
290
291 #pragma mark - Position
292
moveBy(const ScreenCoordinate & point,const AnimationOptions & animation)293 void Map::moveBy(const ScreenCoordinate& point, const AnimationOptions& animation) {
294 impl->cameraMutated = true;
295 impl->transform.moveBy(point, animation);
296 impl->onUpdate();
297 }
298
setLatLng(const LatLng & latLng,const AnimationOptions & animation)299 void Map::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
300 impl->cameraMutated = true;
301 setLatLng(latLng, optional<ScreenCoordinate> {}, animation);
302 }
303
setLatLng(const LatLng & latLng,const EdgeInsets & padding,const AnimationOptions & animation)304 void Map::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const AnimationOptions& animation) {
305 impl->cameraMutated = true;
306 impl->transform.setLatLng(latLng, padding, animation);
307 impl->onUpdate();
308 }
309
setLatLng(const LatLng & latLng,optional<ScreenCoordinate> anchor,const AnimationOptions & animation)310 void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
311 impl->cameraMutated = true;
312 impl->transform.setLatLng(latLng, anchor, animation);
313 impl->onUpdate();
314 }
315
getLatLng(const EdgeInsets & padding) const316 LatLng Map::getLatLng(const EdgeInsets& padding) const {
317 return impl->transform.getLatLng(padding);
318 }
319
resetPosition(const EdgeInsets & padding)320 void Map::resetPosition(const EdgeInsets& padding) {
321 impl->cameraMutated = true;
322 CameraOptions camera;
323 camera.angle = 0;
324 camera.pitch = 0;
325 camera.center = LatLng(0, 0);
326 camera.padding = padding;
327 camera.zoom = 0;
328 impl->transform.jumpTo(camera);
329 impl->onUpdate();
330 }
331
332
333 #pragma mark - Zoom
334
setZoom(double zoom,const AnimationOptions & animation)335 void Map::setZoom(double zoom, const AnimationOptions& animation) {
336 impl->cameraMutated = true;
337 setZoom(zoom, EdgeInsets(), animation);
338 }
339
setZoom(double zoom,optional<ScreenCoordinate> anchor,const AnimationOptions & animation)340 void Map::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
341 impl->cameraMutated = true;
342 impl->transform.setZoom(zoom, anchor, animation);
343 impl->onUpdate();
344 }
345
setZoom(double zoom,const EdgeInsets & padding,const AnimationOptions & animation)346 void Map::setZoom(double zoom, const EdgeInsets& padding, const AnimationOptions& animation) {
347 impl->cameraMutated = true;
348 impl->transform.setZoom(zoom, padding, animation);
349 impl->onUpdate();
350 }
351
getZoom() const352 double Map::getZoom() const {
353 return impl->transform.getZoom();
354 }
355
setLatLngZoom(const LatLng & latLng,double zoom,const AnimationOptions & animation)356 void Map::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOptions& animation) {
357 impl->cameraMutated = true;
358 setLatLngZoom(latLng, zoom, {}, animation);
359 }
360
setLatLngZoom(const LatLng & latLng,double zoom,const EdgeInsets & padding,const AnimationOptions & animation)361 void Map::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& padding, const AnimationOptions& animation) {
362 impl->cameraMutated = true;
363 impl->transform.setLatLngZoom(latLng, zoom, padding, animation);
364 impl->onUpdate();
365 }
366
cameraForLatLngBounds(const LatLngBounds & bounds,const EdgeInsets & padding,optional<double> bearing,optional<double> pitch) const367 CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const {
368 return cameraForLatLngs({
369 bounds.northwest(),
370 bounds.southwest(),
371 bounds.southeast(),
372 bounds.northeast(),
373 }, padding, bearing, pitch);
374 }
375
cameraForLatLngs(const std::vector<LatLng> & latLngs,const Transform & transform,const EdgeInsets & padding)376 CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transform& transform, const EdgeInsets& padding) {
377 CameraOptions options;
378 if (latLngs.empty()) {
379 return options;
380 }
381 Size size = transform.getState().getSize();
382 // Calculate the bounds of the possibly rotated shape with respect to the viewport.
383 ScreenCoordinate nePixel = {-INFINITY, -INFINITY};
384 ScreenCoordinate swPixel = {INFINITY, INFINITY};
385 double viewportHeight = size.height;
386 for (LatLng latLng : latLngs) {
387 ScreenCoordinate pixel = transform.latLngToScreenCoordinate(latLng);
388 swPixel.x = std::min(swPixel.x, pixel.x);
389 nePixel.x = std::max(nePixel.x, pixel.x);
390 swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
391 nePixel.y = std::max(nePixel.y, viewportHeight - pixel.y);
392 }
393 double width = nePixel.x - swPixel.x;
394 double height = nePixel.y - swPixel.y;
395
396 // Calculate the zoom level.
397 double minScale = INFINITY;
398 if (width > 0 || height > 0) {
399 double scaleX = double(size.width) / width;
400 double scaleY = double(size.height) / height;
401 scaleX -= (padding.left() + padding.right()) / width;
402 scaleY -= (padding.top() + padding.bottom()) / height;
403 minScale = util::min(scaleX, scaleY);
404 }
405 double zoom = transform.getZoom() + ::log2(minScale);
406 zoom = util::clamp(zoom, transform.getState().getMinZoom(), transform.getState().getMaxZoom());
407
408 // Calculate the center point of a virtual bounds that is extended in all directions by padding.
409 ScreenCoordinate centerPixel = nePixel + swPixel;
410 ScreenCoordinate paddedNEPixel = {
411 padding.right() / minScale,
412 padding.top() / minScale,
413 };
414 ScreenCoordinate paddedSWPixel = {
415 padding.left() / minScale,
416 padding.bottom() / minScale,
417 };
418 centerPixel = centerPixel + paddedNEPixel - paddedSWPixel;
419 centerPixel /= 2.0;
420
421 // CameraOptions origin is at the top-left corner.
422 centerPixel.y = viewportHeight - centerPixel.y;
423
424 options.center = transform.screenCoordinateToLatLng(centerPixel);
425 options.zoom = zoom;
426 return options;
427 }
428
cameraForLatLngs(const std::vector<LatLng> & latLngs,const EdgeInsets & padding,optional<double> bearing,optional<double> pitch) const429 CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const {
430
431 if (!bearing && !pitch) {
432 return mbgl::cameraForLatLngs(latLngs, impl->transform, padding);
433 }
434
435 Transform transform(impl->transform.getState());
436
437 if (bearing) {
438 double angle = -*bearing * util::DEG2RAD; // Convert to radians
439 transform.setAngle(angle);
440 }
441 if (pitch) {
442 double pitchAsRadian = *pitch * util::DEG2RAD; // Convert to radians
443 transform.setPitch(pitchAsRadian);
444 }
445
446 CameraOptions options = mbgl::cameraForLatLngs(latLngs, transform, padding);
447 options.angle = transform.getAngle();
448 options.pitch = transform.getPitch();
449
450 return options;
451 }
452
cameraForGeometry(const Geometry<double> & geometry,const EdgeInsets & padding,optional<double> bearing,optional<double> pitch) const453 CameraOptions Map::cameraForGeometry(const Geometry<double>& geometry, const EdgeInsets& padding, optional<double> bearing, optional<double> pitch) const {
454
455 std::vector<LatLng> latLngs;
456 forEachPoint(geometry, [&](const Point<double>& pt) {
457 latLngs.push_back({ pt.y, pt.x });
458 });
459 return cameraForLatLngs(latLngs, padding, bearing, pitch);
460 }
461
latLngBoundsForCamera(const CameraOptions & camera) const462 LatLngBounds Map::latLngBoundsForCamera(const CameraOptions& camera) const {
463 Transform shallow { impl->transform.getState() };
464 Size size = shallow.getState().getSize();
465
466 shallow.jumpTo(camera);
467 return LatLngBounds::hull(
468 shallow.screenCoordinateToLatLng({}),
469 shallow.screenCoordinateToLatLng({ double(size.width), double(size.height) })
470 );
471 }
472
resetZoom()473 void Map::resetZoom() {
474 impl->cameraMutated = true;
475 setZoom(0);
476 }
477
478 #pragma mark - Bounds
479
getLatLngBounds() const480 optional<LatLngBounds> Map::getLatLngBounds() const {
481 return impl->transform.getState().getLatLngBounds();
482 }
483
setLatLngBounds(optional<LatLngBounds> bounds)484 void Map::setLatLngBounds(optional<LatLngBounds> bounds) {
485 impl->cameraMutated = true;
486 impl->transform.setLatLngBounds(bounds);
487 impl->onUpdate();
488 }
489
setMinZoom(const double minZoom)490 void Map::setMinZoom(const double minZoom) {
491 impl->transform.setMinZoom(minZoom);
492 if (getZoom() < minZoom) {
493 setZoom(minZoom);
494 }
495 }
496
getMinZoom() const497 double Map::getMinZoom() const {
498 return impl->transform.getState().getMinZoom();
499 }
500
setMaxZoom(const double maxZoom)501 void Map::setMaxZoom(const double maxZoom) {
502 impl->transform.setMaxZoom(maxZoom);
503 if (getZoom() > maxZoom) {
504 setZoom(maxZoom);
505 }
506 }
507
getMaxZoom() const508 double Map::getMaxZoom() const {
509 return impl->transform.getState().getMaxZoom();
510 }
511
setMinPitch(double minPitch)512 void Map::setMinPitch(double minPitch) {
513 impl->transform.setMinPitch(minPitch * util::DEG2RAD);
514 if (getPitch() < minPitch) {
515 setPitch(minPitch);
516 }
517 }
518
getMinPitch() const519 double Map::getMinPitch() const {
520 return impl->transform.getState().getMinPitch() * util::RAD2DEG;
521 }
522
setMaxPitch(double maxPitch)523 void Map::setMaxPitch(double maxPitch) {
524 impl->transform.setMaxPitch(maxPitch * util::DEG2RAD);
525 if (getPitch() > maxPitch) {
526 setPitch(maxPitch);
527 }
528 }
529
getMaxPitch() const530 double Map::getMaxPitch() const {
531 return impl->transform.getState().getMaxPitch() * util::RAD2DEG;
532 }
533
534 #pragma mark - Size
535
setSize(const Size size)536 void Map::setSize(const Size size) {
537 impl->transform.resize(size);
538 impl->onUpdate();
539 }
540
getSize() const541 Size Map::getSize() const {
542 return impl->transform.getState().getSize();
543 }
544
545 #pragma mark - Rotation
546
rotateBy(const ScreenCoordinate & first,const ScreenCoordinate & second,const AnimationOptions & animation)547 void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
548 impl->cameraMutated = true;
549 impl->transform.rotateBy(first, second, animation);
550 impl->onUpdate();
551 }
552
setBearing(double degrees,const AnimationOptions & animation)553 void Map::setBearing(double degrees, const AnimationOptions& animation) {
554 impl->cameraMutated = true;
555 setBearing(degrees, EdgeInsets(), animation);
556 }
557
setBearing(double degrees,optional<ScreenCoordinate> anchor,const AnimationOptions & animation)558 void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
559 impl->cameraMutated = true;
560 impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, animation);
561 impl->onUpdate();
562 }
563
setBearing(double degrees,const EdgeInsets & padding,const AnimationOptions & animation)564 void Map::setBearing(double degrees, const EdgeInsets& padding, const AnimationOptions& animation) {
565 impl->cameraMutated = true;
566 impl->transform.setAngle(-degrees * util::DEG2RAD, padding, animation);
567 impl->onUpdate();
568 }
569
getBearing() const570 double Map::getBearing() const {
571 return -impl->transform.getAngle() * util::RAD2DEG;
572 }
573
resetNorth(const AnimationOptions & animation)574 void Map::resetNorth(const AnimationOptions& animation) {
575 impl->cameraMutated = true;
576 impl->transform.setAngle(0, animation);
577 impl->onUpdate();
578 }
579
580 #pragma mark - Pitch
581
setPitch(double pitch,const AnimationOptions & animation)582 void Map::setPitch(double pitch, const AnimationOptions& animation) {
583 impl->cameraMutated = true;
584 setPitch(pitch, {}, animation);
585 }
586
setPitch(double pitch,optional<ScreenCoordinate> anchor,const AnimationOptions & animation)587 void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
588 impl->cameraMutated = true;
589 impl->transform.setPitch(pitch * util::DEG2RAD, anchor, animation);
590 impl->onUpdate();
591 }
592
getPitch() const593 double Map::getPitch() const {
594 return impl->transform.getPitch() * util::RAD2DEG;
595 }
596
597 #pragma mark - North Orientation
598
setNorthOrientation(NorthOrientation orientation)599 void Map::setNorthOrientation(NorthOrientation orientation) {
600 impl->transform.setNorthOrientation(orientation);
601 impl->onUpdate();
602 }
603
getNorthOrientation() const604 NorthOrientation Map::getNorthOrientation() const {
605 return impl->transform.getNorthOrientation();
606 }
607
608 #pragma mark - Constrain mode
609
setConstrainMode(mbgl::ConstrainMode mode)610 void Map::setConstrainMode(mbgl::ConstrainMode mode) {
611 impl->transform.setConstrainMode(mode);
612 impl->onUpdate();
613 }
614
getConstrainMode() const615 ConstrainMode Map::getConstrainMode() const {
616 return impl->transform.getConstrainMode();
617 }
618
619 #pragma mark - Viewport mode
620
setViewportMode(mbgl::ViewportMode mode)621 void Map::setViewportMode(mbgl::ViewportMode mode) {
622 impl->transform.setViewportMode(mode);
623 impl->onUpdate();
624 }
625
getViewportMode() const626 ViewportMode Map::getViewportMode() const {
627 return impl->transform.getViewportMode();
628 }
629
630 #pragma mark - Projection mode
631
setAxonometric(bool axonometric)632 void Map::setAxonometric(bool axonometric) {
633 impl->transform.setAxonometric(axonometric);
634 impl->onUpdate();
635 }
636
getAxonometric() const637 bool Map::getAxonometric() const {
638 return impl->transform.getAxonometric();
639 }
640
setXSkew(double xSkew)641 void Map::setXSkew(double xSkew) {
642 impl->transform.setXSkew(xSkew);
643 impl->onUpdate();
644 }
645
getXSkew() const646 double Map::getXSkew() const {
647 return impl->transform.getXSkew();
648 }
649
setYSkew(double ySkew)650 void Map::setYSkew(double ySkew) {
651 impl->transform.setYSkew(ySkew);
652 impl->onUpdate();
653 }
654
getYSkew() const655 double Map::getYSkew() const {
656 return impl->transform.getYSkew();
657 }
658
659 #pragma mark - Projection
660
pixelForLatLng(const LatLng & latLng) const661 ScreenCoordinate Map::pixelForLatLng(const LatLng& latLng) const {
662 // If the center and point longitudes are not in the same side of the
663 // antimeridian, we unwrap the point longitude so it would be seen if
664 // e.g. the next antimeridian side is visible.
665 LatLng unwrappedLatLng = latLng.wrapped();
666 unwrappedLatLng.unwrapForShortestPath(getLatLng());
667 return impl->transform.latLngToScreenCoordinate(unwrappedLatLng);
668 }
669
latLngForPixel(const ScreenCoordinate & pixel) const670 LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
671 return impl->transform.screenCoordinateToLatLng(pixel);
672 }
673
674 #pragma mark - Annotations
675
addAnnotationImage(std::unique_ptr<style::Image> image)676 void Map::addAnnotationImage(std::unique_ptr<style::Image> image) {
677 impl->annotationManager.addImage(std::move(image));
678 }
679
removeAnnotationImage(const std::string & id)680 void Map::removeAnnotationImage(const std::string& id) {
681 impl->annotationManager.removeImage(id);
682 }
683
getTopOffsetPixelsForAnnotationImage(const std::string & id)684 double Map::getTopOffsetPixelsForAnnotationImage(const std::string& id) {
685 return impl->annotationManager.getTopOffsetPixelsForImage(id);
686 }
687
addAnnotation(const Annotation & annotation)688 AnnotationID Map::addAnnotation(const Annotation& annotation) {
689 auto result = impl->annotationManager.addAnnotation(annotation);
690 impl->onUpdate();
691 return result;
692 }
693
updateAnnotation(AnnotationID id,const Annotation & annotation)694 void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
695 if (impl->annotationManager.updateAnnotation(id, annotation)) {
696 impl->onUpdate();
697 }
698 }
699
removeAnnotation(AnnotationID annotation)700 void Map::removeAnnotation(AnnotationID annotation) {
701 impl->annotationManager.removeAnnotation(annotation);
702 impl->onUpdate();
703 }
704
705 #pragma mark - Toggles
706
setDebug(MapDebugOptions debugOptions)707 void Map::setDebug(MapDebugOptions debugOptions) {
708 impl->debugOptions = debugOptions;
709 impl->onUpdate();
710 }
711
cycleDebugOptions()712 void Map::cycleDebugOptions() {
713 #if not MBGL_USE_GLES2
714 if (impl->debugOptions & MapDebugOptions::StencilClip)
715 impl->debugOptions = MapDebugOptions::NoDebug;
716 else if (impl->debugOptions & MapDebugOptions::Overdraw)
717 impl->debugOptions = MapDebugOptions::StencilClip;
718 #else
719 if (impl->debugOptions & MapDebugOptions::Overdraw)
720 impl->debugOptions = MapDebugOptions::NoDebug;
721 #endif // MBGL_USE_GLES2
722 else if (impl->debugOptions & MapDebugOptions::Collision)
723 impl->debugOptions = MapDebugOptions::Overdraw;
724 else if (impl->debugOptions & MapDebugOptions::Timestamps)
725 impl->debugOptions = impl->debugOptions | MapDebugOptions::Collision;
726 else if (impl->debugOptions & MapDebugOptions::ParseStatus)
727 impl->debugOptions = impl->debugOptions | MapDebugOptions::Timestamps;
728 else if (impl->debugOptions & MapDebugOptions::TileBorders)
729 impl->debugOptions = impl->debugOptions | MapDebugOptions::ParseStatus;
730 else
731 impl->debugOptions = MapDebugOptions::TileBorders;
732
733 impl->onUpdate();
734 }
735
getDebug() const736 MapDebugOptions Map::getDebug() const {
737 return impl->debugOptions;
738 }
739
setPrefetchZoomDelta(uint8_t delta)740 void Map::setPrefetchZoomDelta(uint8_t delta) {
741 impl->prefetchZoomDelta = delta;
742 }
743
getPrefetchZoomDelta() const744 uint8_t Map::getPrefetchZoomDelta() const {
745 return impl->prefetchZoomDelta;
746 }
747
isFullyLoaded() const748 bool Map::isFullyLoaded() const {
749 return impl->style->impl->isLoaded() && impl->rendererFullyLoaded;
750 }
751
onSourceChanged(style::Source & source)752 void Map::Impl::onSourceChanged(style::Source& source) {
753 observer.onSourceChanged(source);
754 }
755
onInvalidate()756 void Map::Impl::onInvalidate() {
757 onUpdate();
758 }
759
onUpdate()760 void Map::Impl::onUpdate() {
761 // Don't load/render anything in still mode until explicitly requested.
762 if (mode != MapMode::Continuous && !stillImageRequest) {
763 return;
764 }
765
766 TimePoint timePoint = mode == MapMode::Continuous ? Clock::now() : Clock::time_point::max();
767
768 transform.updateTransitions(timePoint);
769
770 UpdateParameters params = {
771 style->impl->isLoaded(),
772 mode,
773 pixelRatio,
774 debugOptions,
775 timePoint,
776 transform.getState(),
777 style->impl->getGlyphURL(),
778 style->impl->spriteLoaded,
779 style->impl->getTransitionOptions(),
780 style->impl->getLight()->impl,
781 style->impl->getImageImpls(),
782 style->impl->getSourceImpls(),
783 style->impl->getLayerImpls(),
784 annotationManager,
785 prefetchZoomDelta,
786 bool(stillImageRequest)
787 };
788
789 rendererFrontend.update(std::make_shared<UpdateParameters>(std::move(params)));
790 }
791
onStyleLoading()792 void Map::Impl::onStyleLoading() {
793 loading = true;
794 rendererFullyLoaded = false;
795 observer.onWillStartLoadingMap();
796 }
797
onStyleLoaded()798 void Map::Impl::onStyleLoaded() {
799 if (!cameraMutated) {
800 map.jumpTo(style->getDefaultCamera());
801 }
802
803 annotationManager.onStyleLoaded();
804 observer.onDidFinishLoadingStyle();
805 }
806
onStyleError(std::exception_ptr error)807 void Map::Impl::onStyleError(std::exception_ptr error) {
808 observer.onDidFailLoadingMap(error);
809 }
810
onResourceError(std::exception_ptr error)811 void Map::Impl::onResourceError(std::exception_ptr error) {
812 if (mode != MapMode::Continuous && stillImageRequest) {
813 auto request = std::move(stillImageRequest);
814 request->callback(error);
815 }
816 }
817
dumpDebugLogs() const818 void Map::dumpDebugLogs() const {
819 Log::Info(Event::General, "--------------------------------------------------------------------------------");
820 impl->style->impl->dumpDebugLogs();
821 Log::Info(Event::General, "--------------------------------------------------------------------------------");
822 }
823
824 } // namespace mbgl
825