map: Transfer to MapLibre (#31185)

* change codebase

* compile

* add mapboxprovider

* works with map_renderer in c

* remove maplibre temp

* maplibre works

* cleanup build.sh

* x86 stuff

* add lib

* update release files

* don't need that

* tici build

* tici build

* add tici lib

* update refs

---------

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
old-commit-hash: 08037594e2
chrysler-long2
Hoang Bui 1 year ago committed by GitHub
parent ac63e9fd51
commit 4c05358aad
  1. 9
      SConstruct
  2. 1
      release/files_common
  3. 2
      release/files_pc
  4. 1
      release/files_tici
  5. 4
      selfdrive/navd/SConscript
  6. 36
      selfdrive/navd/map_renderer.cc
  7. 11
      selfdrive/navd/map_renderer.h
  8. 2
      selfdrive/test/process_replay/model_replay_ref_commit
  9. 6
      selfdrive/ui/SConscript
  10. 39
      selfdrive/ui/qt/maps/map.cc
  11. 13
      selfdrive/ui/qt/maps/map.h
  12. 37
      selfdrive/ui/qt/maps/map_helpers.cc
  13. 17
      selfdrive/ui/qt/maps/map_helpers.h
  14. 2
      selfdrive/ui/qt/maps/map_panel.cc
  15. 4
      selfdrive/ui/qt/maps/map_panel.h
  16. 2
      third_party/mapbox-gl-native-qt/.gitattributes
  17. 3
      third_party/mapbox-gl-native-qt/aarch64/libqmapboxgl.so
  18. 7
      third_party/mapbox-gl-native-qt/build.sh
  19. 1
      third_party/mapbox-gl-native-qt/include/QMapbox
  20. 1
      third_party/mapbox-gl-native-qt/include/QMapboxGL
  21. 147
      third_party/mapbox-gl-native-qt/include/qmapbox.hpp
  22. 277
      third_party/mapbox-gl-native-qt/include/qmapboxgl.hpp
  23. 3
      third_party/mapbox-gl-native-qt/x86_64/libqmapboxgl.so
  24. 1
      third_party/maplibre-native-qt/.gitignore
  25. 1
      third_party/maplibre-native-qt/aarch64
  26. 38
      third_party/maplibre-native-qt/build.sh
  27. 241
      third_party/maplibre-native-qt/include/conversion_p.hpp
  28. 20
      third_party/maplibre-native-qt/include/export_core.hpp
  29. 20
      third_party/maplibre-native-qt/include/export_location.hpp
  30. 20
      third_party/maplibre-native-qt/include/export_widgets.hpp
  31. 30
      third_party/maplibre-native-qt/include/geojson_p.hpp
  32. 56
      third_party/maplibre-native-qt/include/gl_widget.hpp
  33. 42
      third_party/maplibre-native-qt/include/gl_widget_p.hpp
  34. 205
      third_party/maplibre-native-qt/include/map.hpp
  35. 54
      third_party/maplibre-native-qt/include/map_observer_p.hpp
  36. 79
      third_party/maplibre-native-qt/include/map_p.hpp
  37. 63
      third_party/maplibre-native-qt/include/map_renderer_p.hpp
  38. 54
      third_party/maplibre-native-qt/include/qgeomap.hpp
  39. 93
      third_party/maplibre-native-qt/include/qgeomap_p.hpp
  40. 9
      third_party/maplibre-native-qt/include/qmaplibre.hpp
  41. 6
      third_party/maplibre-native-qt/include/qmaplibrewidgets.hpp
  42. 31
      third_party/maplibre-native-qt/include/qt_mapping_engine.hpp
  43. 125
      third_party/maplibre-native-qt/include/settings.hpp
  44. 57
      third_party/maplibre-native-qt/include/settings_p.hpp
  45. 34
      third_party/maplibre-native-qt/include/style_change_utils_p.hpp
  46. 42
      third_party/maplibre-native-qt/include/texture_node.hpp
  47. 206
      third_party/maplibre-native-qt/include/types.hpp
  48. 28
      third_party/maplibre-native-qt/include/utils.hpp
  49. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/Export
  50. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/LayerParameter
  51. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/Map
  52. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/QMapLibre
  53. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/Settings
  54. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/SourceParameter
  55. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/StyleParameter
  56. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/Types
  57. 1
      third_party/maplibre-native-qt/larch64/include/QMapLibre/Utils
  58. 3
      third_party/maplibre-native-qt/larch64/lib/libQMapLibre.so
  59. 3
      third_party/maplibre-native-qt/larch64/lib/libQMapLibre.so.3.0.0
  60. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/Export
  61. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/LayerParameter
  62. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/Map
  63. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/QMapLibre
  64. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/Settings
  65. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/SourceParameter
  66. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/StyleParameter
  67. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/Types
  68. 1
      third_party/maplibre-native-qt/x86_64/include/QMapLibre/Utils
  69. 1
      third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so
  70. 3
      third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so.3.0.0

@ -145,7 +145,6 @@ else:
libpath = [
f"#third_party/acados/{arch}/lib",
f"#third_party/libyuv/{arch}/lib",
f"#third_party/mapbox-gl-native-qt/{arch}",
"/usr/lib",
"/usr/local/lib",
]
@ -208,11 +207,12 @@ env = Environment(
"#third_party/json11",
"#third_party/linux/include",
"#third_party/snpe/include",
"#third_party/mapbox-gl-native-qt/include",
"#third_party/qrcode",
"#third_party",
"#cereal",
"#opendbc/can",
"#third_party/maplibre-native-qt/include",
f"#third_party/maplibre-native-qt/{arch}/include"
],
CC='clang',
@ -318,7 +318,7 @@ try:
except SCons.Errors.UserError:
qt_env.Tool('qt')
qt_env['CPPPATH'] += qt_dirs + ["#selfdrive/ui/qt/"]
qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"]
qt_flags = [
"-D_REENTRANT",
"-DQT_NO_DEBUG",
@ -331,7 +331,8 @@ qt_flags = [
"-DQT_MESSAGELOGCONTEXT",
]
qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBPATH'] += ['#selfdrive/ui', f"#third_party/maplibre-native-qt/{arch}/lib"]
qt_env['RPATH'] += [Dir(f"#third_party/maplibre-native-qt/{arch}/lib").srcnode().abspath]
qt_env['LIBS'] = qt_libs
if GetOption("clazy"):

@ -394,6 +394,7 @@ third_party/acados/acados_template/**
third_party/bootstrap/**
third_party/qt5/larch64/bin/**
third_party/maplibre-native-qt/**
scripts/update_now.sh
scripts/stop_updater.sh

@ -1,5 +1,3 @@
third_party/mapbox-gl-native-qt/x86_64/*.so
third_party/libyuv/x86_64/**
third_party/snpe/x86_64/**
third_party/snpe/x86_64-linux-clang/**

@ -1,7 +1,6 @@
third_party/libyuv/larch64/**
third_party/snpe/larch64**
third_party/snpe/aarch64-ubuntu-gcc7.5/*
third_party/mapbox-gl-native-qt/include/*
third_party/acados/larch64/**
system/camerad/cameras/camera_qcom2.cc

@ -1,14 +1,14 @@
Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transformations')
map_env = qt_env.Clone()
libs = ['qt_widgets', 'qt_util', 'qmapboxgl', common, messaging, cereal, visionipc, transformations,
libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, cereal, visionipc, transformations,
'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"]
if arch == 'larch64':
libs.append(':libEGL_mesa.so.0')
if arch in ['larch64', 'aarch64', 'x86_64']:
if arch == 'x86_64':
rpath = Dir(f"#third_party/mapbox-gl-native-qt/{arch}").srcnode().abspath
rpath = Dir(f"#third_party/maplibre-native-qt/{arch}/lib").srcnode().abspath
map_env["RPATH"] += [rpath, ]
style_path = File("style.json").abspath

@ -28,16 +28,16 @@ float get_zoom_level_for_scale(float lat, float meters_per_pixel) {
return log2(num_tiles) - 1;
}
QMapbox::Coordinate get_point_along_line(float lat, float lon, float bearing, float dist) {
QMapLibre::Coordinate get_point_along_line(float lat, float lon, float bearing, float dist) {
float ang_dist = dist / EARTH_RADIUS_METERS;
float lat1 = DEG2RAD(lat), lon1 = DEG2RAD(lon), bearing1 = DEG2RAD(bearing);
float lat2 = asin(sin(lat1)*cos(ang_dist) + cos(lat1)*sin(ang_dist)*cos(bearing1));
float lon2 = lon1 + atan2(sin(bearing1)*sin(ang_dist)*cos(lat1), cos(ang_dist)-sin(lat1)*sin(lat2));
return QMapbox::Coordinate(RAD2DEG(lat2), RAD2DEG(lon2));
return QMapLibre::Coordinate(RAD2DEG(lat2), RAD2DEG(lon2));
}
MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_settings(settings) {
MapRenderer::MapRenderer(const QMapLibre::Settings &settings, bool online) : m_settings(settings) {
QSurfaceFormat fmt;
fmt.setRenderableType(QSurfaceFormat::OpenGLES);
@ -60,8 +60,8 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set
fbo.reset(new QOpenGLFramebufferObject(WIDTH, HEIGHT, fbo_format));
std::string style = util::read_file(STYLE_PATH);
m_map.reset(new QMapboxGL(nullptr, m_settings, fbo->size(), 1));
m_map->setCoordinateZoom(QMapbox::Coordinate(0, 0), DEFAULT_ZOOM);
m_map.reset(new QMapLibre::Map(nullptr, m_settings, fbo->size(), 1));
m_map->setCoordinateZoom(QMapLibre::Coordinate(0, 0), DEFAULT_ZOOM);
m_map->setStyleJson(style.c_str());
m_map->createRenderer();
ever_loaded = false;
@ -70,20 +70,20 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set
m_map->setFramebufferObject(fbo->handle(), fbo->size());
gl_functions->glViewport(0, 0, WIDTH, HEIGHT);
QObject::connect(m_map.data(), &QMapboxGL::mapChanged, [=](QMapboxGL::MapChange change) {
QObject::connect(m_map.data(), &QMapLibre::Map::mapChanged, [=](QMapLibre::Map::MapChange change) {
// Ignore expected signals
// https://github.com/mapbox/mapbox-gl-native/blob/cf734a2fec960025350d8de0d01ad38aeae155a0/platform/qt/include/qmapboxgl.hpp#L116
if (ever_loaded) {
if (change != QMapboxGL::MapChange::MapChangeRegionWillChange &&
change != QMapboxGL::MapChange::MapChangeRegionDidChange &&
change != QMapboxGL::MapChange::MapChangeWillStartRenderingFrame &&
change != QMapboxGL::MapChange::MapChangeDidFinishRenderingFrameFullyRendered) {
if (change != QMapLibre::Map::MapChange::MapChangeRegionWillChange &&
change != QMapLibre::Map::MapChange::MapChangeRegionDidChange &&
change != QMapLibre::Map::MapChange::MapChangeWillStartRenderingFrame &&
change != QMapLibre::Map::MapChange::MapChangeDidFinishRenderingFrameFullyRendered) {
LOGD("New map state: %d", change);
}
}
});
QObject::connect(m_map.data(), &QMapboxGL::mapLoadingFailed, [=](QMapboxGL::MapLoadingFailure err_code, const QString &reason) {
QObject::connect(m_map.data(), &QMapLibre::Map::mapLoadingFailed, [=](QMapLibre::Map::MapLoadingFailure err_code, const QString &reason) {
LOGE("Map loading failed with %d: '%s'\n", err_code, reason.toStdString().c_str());
});
@ -145,7 +145,7 @@ void MapRenderer::msgUpdate() {
timer->start(0);
}
void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) {
void MapRenderer::updatePosition(QMapLibre::Coordinate position, float bearing) {
if (m_map.isNull()) {
return;
}
@ -261,10 +261,10 @@ void MapRenderer::updateRoute(QList<QGeoCoordinate> coordinates) {
initLayers();
auto route_points = coordinate_list_to_collection(coordinates);
QMapbox::Feature feature(QMapbox::Feature::LineStringType, route_points, {}, {});
QMapLibre::Feature feature(QMapLibre::Feature::LineStringType, route_points, {}, {});
QVariantMap navSource;
navSource["type"] = "geojson";
navSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature);
navSource["data"] = QVariant::fromValue<QMapLibre::Feature>(feature);
m_map->updateSource("navSource", navSource);
m_map->setLayoutProperty("navLayer", "visibility", "visible");
}
@ -273,10 +273,9 @@ void MapRenderer::initLayers() {
if (!m_map->layerExists("navLayer")) {
LOGD("Initializing navLayer");
QVariantMap nav;
nav["id"] = "navLayer";
nav["type"] = "line";
nav["source"] = "navSource";
m_map->addLayer(nav, "road-intersection");
m_map->addLayer("navLayer", nav, "road-intersection");
m_map->setPaintProperty("navLayer", "line-color", QColor("grey"));
m_map->setPaintProperty("navLayer", "line-width", 5);
m_map->setLayoutProperty("navLayer", "line-cap", "round");
@ -296,9 +295,10 @@ extern "C" {
QApplication *app = new QApplication(argc, argv);
assert(app);
QMapboxGLSettings settings;
QMapLibre::Settings settings;
settings.setProviderTemplate(QMapLibre::Settings::ProviderTemplate::MapboxProvider);
settings.setApiBaseUrl(maps_host == nullptr ? MAPS_HOST : maps_host);
settings.setAccessToken(token == nullptr ? get_mapbox_token() : token);
settings.setApiKey(token == nullptr ? get_mapbox_token() : token);
return new MapRenderer(settings, false);
}

@ -3,7 +3,8 @@
#include <memory>
#include <QOpenGLContext>
#include <QMapboxGL>
#include <QMapLibre/Map>
#include <QMapLibre/Settings>
#include <QTimer>
#include <QGeoCoordinate>
#include <QOpenGLBuffer>
@ -19,7 +20,7 @@ class MapRenderer : public QObject {
Q_OBJECT
public:
MapRenderer(const QMapboxGLSettings &, bool online=true);
MapRenderer(const QMapLibre::Settings &, bool online=true);
uint8_t* getImage();
void update();
bool loaded();
@ -37,8 +38,8 @@ private:
void publish(const double render_time, const bool loaded);
void sendThumbnail(const uint64_t ts, const kj::Array<capnp::byte> &buf);
QMapboxGLSettings m_settings;
QScopedPointer<QMapboxGL> m_map;
QMapLibre::Settings m_settings;
QScopedPointer<QMapLibre::Map> m_map;
void initLayers();
@ -52,7 +53,7 @@ private:
bool ever_loaded = false;
public slots:
void updatePosition(QMapbox::Coordinate position, float bearing);
void updatePosition(QMapLibre::Coordinate position, float bearing);
void updateRoute(QList<QGeoCoordinate> coordinates);
void msgUpdate();
};

@ -1 +1 @@
4a01784a6b83a49301a68adf52bb7dcfcb7173b5
fee90bcee1e545c7ec9a39d3c7d4e42cfefb9955

@ -11,10 +11,6 @@ if arch == 'larch64':
maps = arch in ['larch64', 'aarch64', 'x86_64']
if maps and arch != 'larch64':
rpath = [Dir(f"#third_party/mapbox-gl-native-qt/{arch}").srcnode().abspath]
qt_env["RPATH"] += rpath
if arch == "Darwin":
del base_libs[base_libs.index('OpenCL')]
qt_env['FRAMEWORKS'] += ['OpenCL']
@ -31,7 +27,7 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc",
qt_env['CPPDEFINES'] = []
if maps:
base_libs += ['qmapboxgl']
base_libs += ['QMapLibre']
widgets_src += ["qt/maps/map_helpers.cc", "qt/maps/map_settings.cc", "qt/maps/map.cc", "qt/maps/map_panel.cc",
"qt/maps/map_eta.cc", "qt/maps/map_instructions.cc"]
qt_env['CPPDEFINES'] += ["ENABLE_MAPS"]

@ -18,7 +18,7 @@ const float MAX_PITCH = 50;
const float MIN_PITCH = 0;
const float MAP_SCALE = 2;
MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings), velocity_filter(0, 10, 0.05, false) {
MapWindow::MapWindow(const QMapLibre::Settings &settings) : m_settings(settings), velocity_filter(0, 10, 0.05, false) {
QObject::connect(uiState(), &UIState::uiUpdate, this, &MapWindow::updateState);
map_overlay = new QWidget (this);
@ -57,10 +57,10 @@ void MapWindow::initLayers() {
if (!m_map->layerExists("modelPathLayer")) {
qDebug() << "Initializing modelPathLayer";
QVariantMap modelPath;
modelPath["id"] = "modelPathLayer";
//modelPath["id"] = "modelPathLayer";
modelPath["type"] = "line";
modelPath["source"] = "modelPathSource";
m_map->addLayer(modelPath);
m_map->addLayer("modelPathLayer", modelPath);
m_map->setPaintProperty("modelPathLayer", "line-color", QColor("red"));
m_map->setPaintProperty("modelPathLayer", "line-width", 5.0);
m_map->setLayoutProperty("modelPathLayer", "line-cap", "round");
@ -68,10 +68,9 @@ void MapWindow::initLayers() {
if (!m_map->layerExists("navLayer")) {
qDebug() << "Initializing navLayer";
QVariantMap nav;
nav["id"] = "navLayer";
nav["type"] = "line";
nav["source"] = "navSource";
m_map->addLayer(nav, "road-intersection");
m_map->addLayer("navLayer", nav, "road-intersection");
QVariantMap transition;
transition["duration"] = 400; // ms
@ -84,10 +83,9 @@ void MapWindow::initLayers() {
qDebug() << "Initializing pinLayer";
m_map->addImage("default_marker", QImage("../assets/navigation/default_marker.svg"));
QVariantMap pin;
pin["id"] = "pinLayer";
pin["type"] = "symbol";
pin["source"] = "pinSource";
m_map->addLayer(pin);
m_map->addLayer("pinLayer", pin);
m_map->setLayoutProperty("pinLayer", "icon-pitch-alignment", "viewport");
m_map->setLayoutProperty("pinLayer", "icon-image", "default_marker");
m_map->setLayoutProperty("pinLayer", "icon-ignore-placement", true);
@ -100,10 +98,9 @@ void MapWindow::initLayers() {
m_map->addImage("label-arrow", QImage("../assets/images/triangle.svg"));
QVariantMap carPos;
carPos["id"] = "carPosLayer";
carPos["type"] = "symbol";
carPos["source"] = "carPosSource";
m_map->addLayer(carPos);
m_map->addLayer("carPosLayer", carPos);
m_map->setLayoutProperty("carPosLayer", "icon-pitch-alignment", "map");
m_map->setLayoutProperty("carPosLayer", "icon-image", "label-arrow");
m_map->setLayoutProperty("carPosLayer", "icon-size", 0.5);
@ -149,7 +146,7 @@ void MapWindow::updateState(const UIState &s) {
locationd_valid = (locationd_pos.getValid() && locationd_orientation.getValid() && locationd_velocity.getValid() && pos_accurate_enough);
if (locationd_valid) {
last_position = QMapbox::Coordinate(locationd_pos.getValue()[0], locationd_pos.getValue()[1]);
last_position = QMapLibre::Coordinate(locationd_pos.getValue()[0], locationd_pos.getValue()[1]);
last_bearing = RAD2DEG(locationd_orientation.getValue()[2]);
velocity_filter.update(std::max(10.0, locationd_velocity.getValue()[0]));
}
@ -186,10 +183,10 @@ void MapWindow::updateState(const UIState &s) {
if (locationd_valid) {
// Update current location marker
auto point = coordinate_to_collection(*last_position);
QMapbox::Feature feature1(QMapbox::Feature::PointType, point, {}, {});
QMapLibre::Feature feature1(QMapLibre::Feature::PointType, point, {}, {});
QVariantMap carPosSource;
carPosSource["type"] = "geojson";
carPosSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature1);
carPosSource["data"] = QVariant::fromValue<QMapLibre::Feature>(feature1);
m_map->updateSource("carPosSource", carPosSource);
// Map bearing isn't updated when interacting, keep location marker up to date
@ -230,10 +227,10 @@ void MapWindow::updateState(const UIState &s) {
qWarning() << "Updating navLayer with new route";
auto route = sm["navRoute"].getNavRoute();
auto route_points = capnp_coordinate_list_to_collection(route.getCoordinates());
QMapbox::Feature feature(QMapbox::Feature::LineStringType, route_points, {}, {});
QMapLibre::Feature feature(QMapLibre::Feature::LineStringType, route_points, {}, {});
QVariantMap navSource;
navSource["type"] = "geojson";
navSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature);
navSource["data"] = QVariant::fromValue<QMapLibre::Feature>(feature);
m_map->updateSource("navSource", navSource);
m_map->setLayoutProperty("navLayer", "visibility", "visible");
@ -256,24 +253,24 @@ void MapWindow::resizeGL(int w, int h) {
}
void MapWindow::initializeGL() {
m_map.reset(new QMapboxGL(this, m_settings, size(), 1));
m_map.reset(new QMapLibre::Map(this, m_settings, size(), 1));
if (last_position) {
m_map->setCoordinateZoom(*last_position, MAX_ZOOM);
} else {
m_map->setCoordinateZoom(QMapbox::Coordinate(64.31990695292795, -149.79038934046247), MIN_ZOOM);
m_map->setCoordinateZoom(QMapLibre::Coordinate(64.31990695292795, -149.79038934046247), MIN_ZOOM);
}
m_map->setMargins({0, 350, 0, 50});
m_map->setPitch(MIN_PITCH);
m_map->setStyleUrl("mapbox://styles/commaai/clkqztk0f00ou01qyhsa5bzpj");
QObject::connect(m_map.data(), &QMapboxGL::mapChanged, [=](QMapboxGL::MapChange change) {
QObject::connect(m_map.data(), &QMapLibre::Map::mapChanged, [=](QMapLibre::Map::MapChange change) {
// set global animation duration to 0 ms so visibility changes are instant
if (change == QMapboxGL::MapChange::MapChangeDidFinishLoadingStyle) {
if (change == QMapLibre::Map::MapChange::MapChangeDidFinishLoadingStyle) {
m_map->setTransitionOptions(0, 0);
}
if (change == QMapboxGL::MapChange::MapChangeDidFinishLoadingMap) {
if (change == QMapLibre::Map::MapChange::MapChangeDidFinishLoadingMap) {
loaded_once = true;
}
});
@ -381,10 +378,10 @@ void MapWindow::updateDestinationMarker() {
auto nav_dest = coordinate_from_param("NavDestination");
if (nav_dest.has_value()) {
auto point = coordinate_to_collection(*nav_dest);
QMapbox::Feature feature(QMapbox::Feature::PointType, point, {}, {});
QMapLibre::Feature feature(QMapLibre::Feature::PointType, point, {}, {});
QVariantMap pinSource;
pinSource["type"] = "geojson";
pinSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature);
pinSource["data"] = QVariant::fromValue<QMapLibre::Feature>(feature);
m_map->updateSource("pinSource", pinSource);
m_map->setPaintProperty("pinLayer", "visibility", "visible");
} else {

@ -6,7 +6,8 @@
#include <QGestureEvent>
#include <QLabel>
#include <QMap>
#include <QMapboxGL>
#include <QMapLibre/Map>
#include <QMapLibre/Settings>
#include <QMouseEvent>
#include <QOpenGLWidget>
#include <QPixmap>
@ -27,7 +28,7 @@ class MapWindow : public QOpenGLWidget {
Q_OBJECT
public:
MapWindow(const QMapboxGLSettings &);
MapWindow(const QMapLibre::Settings &);
~MapWindow();
private:
@ -35,8 +36,8 @@ private:
void paintGL() final;
void resizeGL(int w, int h) override;
QMapboxGLSettings m_settings;
QScopedPointer<QMapboxGL> m_map;
QMapLibre::Settings m_settings;
QScopedPointer<QMapLibre::Map> m_map;
void initLayers();
@ -56,8 +57,8 @@ private:
int interaction_counter = 0;
// Position
std::optional<QMapbox::Coordinate> last_valid_nav_dest;
std::optional<QMapbox::Coordinate> last_position;
std::optional<QMapLibre::Coordinate> last_valid_nav_dest;
std::optional<QMapLibre::Coordinate> last_position;
std::optional<float> last_bearing;
FirstOrderFilter velocity_filter;
bool locationd_valid = false;

@ -16,24 +16,25 @@ QString get_mapbox_token() {
return MAPBOX_TOKEN.isEmpty() ? CommaApi::create_jwt({}, 4 * 7 * 24 * 3600) : MAPBOX_TOKEN;
}
QMapboxGLSettings get_mapbox_settings() {
QMapboxGLSettings settings;
QMapLibre::Settings get_mapbox_settings() {
QMapLibre::Settings settings;
settings.setProviderTemplate(QMapLibre::Settings::ProviderTemplate::MapboxProvider);
if (!Hardware::PC()) {
settings.setCacheDatabasePath(MAPS_CACHE_PATH);
settings.setCacheDatabaseMaximumSize(100 * 1024 * 1024);
}
settings.setApiBaseUrl(MAPS_HOST);
settings.setAccessToken(get_mapbox_token());
settings.setApiKey(get_mapbox_token());
return settings;
}
QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in) {
QGeoCoordinate to_QGeoCoordinate(const QMapLibre::Coordinate &in) {
return QGeoCoordinate(in.first, in.second);
}
QMapbox::CoordinatesCollections model_to_collection(
QMapLibre::CoordinatesCollections model_to_collection(
const cereal::LiveLocationKalman::Measurement::Reader &calibratedOrientationECEF,
const cereal::LiveLocationKalman::Measurement::Reader &positionECEF,
const cereal::XYZTData::Reader &line){
@ -42,7 +43,7 @@ QMapbox::CoordinatesCollections model_to_collection(
Eigen::Vector3d orient(calibratedOrientationECEF.getValue()[0], calibratedOrientationECEF.getValue()[1], calibratedOrientationECEF.getValue()[2]);
Eigen::Matrix3d ecef_from_local = euler2rot(orient);
QMapbox::Coordinates coordinates;
QMapLibre::Coordinates coordinates;
auto x = line.getX();
auto y = line.getY();
auto z = line.getZ();
@ -52,28 +53,28 @@ QMapbox::CoordinatesCollections model_to_collection(
coordinates.push_back({point_geodetic.lat, point_geodetic.lon});
}
return {QMapbox::CoordinatesCollection{coordinates}};
return {QMapLibre::CoordinatesCollection{coordinates}};
}
QMapbox::CoordinatesCollections coordinate_to_collection(const QMapbox::Coordinate &c) {
QMapbox::Coordinates coordinates{c};
return {QMapbox::CoordinatesCollection{coordinates}};
QMapLibre::CoordinatesCollections coordinate_to_collection(const QMapLibre::Coordinate &c) {
QMapLibre::Coordinates coordinates{c};
return {QMapLibre::CoordinatesCollection{coordinates}};
}
QMapbox::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List<cereal::NavRoute::Coordinate>::Reader& coordinate_list) {
QMapbox::Coordinates coordinates;
QMapLibre::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List<cereal::NavRoute::Coordinate>::Reader& coordinate_list) {
QMapLibre::Coordinates coordinates;
for (auto const &c : coordinate_list) {
coordinates.push_back({c.getLatitude(), c.getLongitude()});
}
return {QMapbox::CoordinatesCollection{coordinates}};
return {QMapLibre::CoordinatesCollection{coordinates}};
}
QMapbox::CoordinatesCollections coordinate_list_to_collection(const QList<QGeoCoordinate> &coordinate_list) {
QMapbox::Coordinates coordinates;
QMapLibre::CoordinatesCollections coordinate_list_to_collection(const QList<QGeoCoordinate> &coordinate_list) {
QMapLibre::Coordinates coordinates;
for (auto &c : coordinate_list) {
coordinates.push_back({c.latitude(), c.longitude()});
}
return {QMapbox::CoordinatesCollection{coordinates}};
return {QMapLibre::CoordinatesCollection{coordinates}};
}
QList<QGeoCoordinate> polyline_to_coordinate_list(const QString &polylineString) {
@ -118,7 +119,7 @@ QList<QGeoCoordinate> polyline_to_coordinate_list(const QString &polylineString)
return path;
}
std::optional<QMapbox::Coordinate> coordinate_from_param(const std::string &param) {
std::optional<QMapLibre::Coordinate> coordinate_from_param(const std::string &param) {
QString json_str = QString::fromStdString(Params().get(param));
if (json_str.isEmpty()) return {};
@ -127,7 +128,7 @@ std::optional<QMapbox::Coordinate> coordinate_from_param(const std::string &para
QJsonObject json = doc.object();
if (json["latitude"].isDouble() && json["longitude"].isDouble()) {
QMapbox::Coordinate coord(json["latitude"].toDouble(), json["longitude"].toDouble());
QMapLibre::Coordinate coord(json["latitude"].toDouble(), json["longitude"].toDouble());
return coord;
} else {
return {};

@ -3,8 +3,9 @@
#include <optional>
#include <string>
#include <utility>
#include <QMapLibre/Map>
#include <QMapLibre/Settings>
#include <eigen3/Eigen/Dense>
#include <QMapboxGL>
#include <QGeoCoordinate>
#include "common/util.h"
@ -17,15 +18,15 @@ const QString MAPS_HOST = util::getenv("MAPS_HOST", MAPBOX_TOKEN.isEmpty() ? "ht
const QString MAPS_CACHE_PATH = "/data/mbgl-cache-navd.db";
QString get_mapbox_token();
QMapboxGLSettings get_mapbox_settings();
QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in);
QMapbox::CoordinatesCollections model_to_collection(
QMapLibre::Settings get_mapbox_settings();
QGeoCoordinate to_QGeoCoordinate(const QMapLibre::Coordinate &in);
QMapLibre::CoordinatesCollections model_to_collection(
const cereal::LiveLocationKalman::Measurement::Reader &calibratedOrientationECEF,
const cereal::LiveLocationKalman::Measurement::Reader &positionECEF,
const cereal::XYZTData::Reader &line);
QMapbox::CoordinatesCollections coordinate_to_collection(const QMapbox::Coordinate &c);
QMapbox::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List<cereal::NavRoute::Coordinate>::Reader &coordinate_list);
QMapbox::CoordinatesCollections coordinate_list_to_collection(const QList<QGeoCoordinate> &coordinate_list);
QMapLibre::CoordinatesCollections coordinate_to_collection(const QMapLibre::Coordinate &c);
QMapLibre::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List<cereal::NavRoute::Coordinate>::Reader &coordinate_list);
QMapLibre::CoordinatesCollections coordinate_list_to_collection(const QList<QGeoCoordinate> &coordinate_list);
QList<QGeoCoordinate> polyline_to_coordinate_list(const QString &polylineString);
std::optional<QMapbox::Coordinate> coordinate_from_param(const std::string &param);
std::optional<QMapLibre::Coordinate> coordinate_from_param(const std::string &param);
std::pair<QString, QString> map_format_distance(float d, bool is_metric);

@ -8,7 +8,7 @@
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/ui.h"
MapPanel::MapPanel(const QMapboxGLSettings &mapboxSettings, QWidget *parent) : QFrame(parent) {
MapPanel::MapPanel(const QMapLibre::Settings &mapboxSettings, QWidget *parent) : QFrame(parent) {
content_stack = new QStackedLayout(this);
content_stack->setContentsMargins(0, 0, 0, 0);

@ -1,14 +1,14 @@
#pragma once
#include <QFrame>
#include <QMapboxGL>
#include <QMapLibre/Settings>
#include <QStackedLayout>
class MapPanel : public QFrame {
Q_OBJECT
public:
explicit MapPanel(const QMapboxGLSettings &settings, QWidget *parent = nullptr);
explicit MapPanel(const QMapLibre::Settings &settings, QWidget *parent = nullptr);
signals:
void mapPanelRequested();

@ -1,2 +0,0 @@
x86_64 filter=lfs diff=lfs merge=lfs -text
larch64 filter=lfs diff=lfs merge=lfs -text

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7fb33cb09b184a689eaa7f78c839d12a5bdd5b6f576d55758ec7e1246187a53f
size 9300680

@ -1,7 +0,0 @@
#!/usr/bin/env sh
cd /tmp
git clone --recursive https://github.com/commaai/mapbox-gl-native.git
cd mapbox-gl-native
mkdir build && cd build
cmake -DMBGL_WITH_QT=ON ..
make -j$(nproc) mbgl-qt

@ -1 +0,0 @@
#include "qmapbox.hpp"

@ -1 +0,0 @@
#include "qmapboxgl.hpp"

@ -1,147 +0,0 @@
#ifndef QMAPBOX_H
#define QMAPBOX_H
#include <QColor>
#include <QPair>
#include <QString>
#include <QVariant>
#include <QVector>
// This header follows the Qt coding style: https://wiki.qt.io/Qt_Coding_Style
#if !defined(QT_MAPBOXGL_STATIC)
# if defined(QT_BUILD_MAPBOXGL_LIB)
# define Q_MAPBOXGL_EXPORT Q_DECL_EXPORT
# else
# define Q_MAPBOXGL_EXPORT Q_DECL_IMPORT
# endif
#else
# define Q_MAPBOXGL_EXPORT
#endif
namespace QMapbox {
typedef QPair<double, double> Coordinate;
typedef QPair<Coordinate, double> CoordinateZoom;
typedef QPair<double, double> ProjectedMeters;
typedef QVector<Coordinate> Coordinates;
typedef QVector<Coordinates> CoordinatesCollection;
typedef QVector<CoordinatesCollection> CoordinatesCollections;
struct Q_MAPBOXGL_EXPORT Feature {
enum Type {
PointType = 1,
LineStringType,
PolygonType
};
/*! Class constructor. */
Feature(Type type_ = PointType, const CoordinatesCollections& geometry_ = CoordinatesCollections(),
const QVariantMap& properties_ = QVariantMap(), const QVariant& id_ = QVariant())
: type(type_), geometry(geometry_), properties(properties_), id(id_) {}
Type type;
CoordinatesCollections geometry;
QVariantMap properties;
QVariant id;
};
struct Q_MAPBOXGL_EXPORT ShapeAnnotationGeometry {
enum Type {
LineStringType = 1,
PolygonType,
MultiLineStringType,
MultiPolygonType
};
/*! Class constructor. */
ShapeAnnotationGeometry(Type type_ = LineStringType, const CoordinatesCollections& geometry_ = CoordinatesCollections())
: type(type_), geometry(geometry_) {}
Type type;
CoordinatesCollections geometry;
};
struct Q_MAPBOXGL_EXPORT SymbolAnnotation {
Coordinate geometry;
QString icon;
};
struct Q_MAPBOXGL_EXPORT LineAnnotation {
/*! Class constructor. */
LineAnnotation(const ShapeAnnotationGeometry& geometry_ = ShapeAnnotationGeometry(), float opacity_ = 1.0f,
float width_ = 1.0f, const QColor& color_ = Qt::black)
: geometry(geometry_), opacity(opacity_), width(width_), color(color_) {}
ShapeAnnotationGeometry geometry;
float opacity;
float width;
QColor color;
};
struct Q_MAPBOXGL_EXPORT FillAnnotation {
/*! Class constructor. */
FillAnnotation(const ShapeAnnotationGeometry& geometry_ = ShapeAnnotationGeometry(), float opacity_ = 1.0f,
const QColor& color_ = Qt::black, const QVariant& outlineColor_ = QVariant())
: geometry(geometry_), opacity(opacity_), color(color_), outlineColor(outlineColor_) {}
ShapeAnnotationGeometry geometry;
float opacity;
QColor color;
QVariant outlineColor;
};
typedef QVariant Annotation;
typedef quint32 AnnotationID;
typedef QVector<AnnotationID> AnnotationIDs;
enum NetworkMode {
Online, // Default
Offline,
};
Q_MAPBOXGL_EXPORT QVector<QPair<QString, QString> >& defaultStyles();
Q_MAPBOXGL_EXPORT NetworkMode networkMode();
Q_MAPBOXGL_EXPORT void setNetworkMode(NetworkMode);
// This struct is a 1:1 copy of mbgl::CustomLayerRenderParameters.
struct Q_MAPBOXGL_EXPORT CustomLayerRenderParameters {
double width;
double height;
double latitude;
double longitude;
double zoom;
double bearing;
double pitch;
double fieldOfView;
};
class Q_MAPBOXGL_EXPORT CustomLayerHostInterface {
public:
virtual ~CustomLayerHostInterface() = default;
virtual void initialize() = 0;
virtual void render(const CustomLayerRenderParameters&) = 0;
virtual void deinitialize() = 0;
};
Q_MAPBOXGL_EXPORT double metersPerPixelAtLatitude(double latitude, double zoom);
Q_MAPBOXGL_EXPORT ProjectedMeters projectedMetersForCoordinate(const Coordinate &);
Q_MAPBOXGL_EXPORT Coordinate coordinateForProjectedMeters(const ProjectedMeters &);
} // namespace QMapbox
Q_DECLARE_METATYPE(QMapbox::Coordinate);
Q_DECLARE_METATYPE(QMapbox::Coordinates);
Q_DECLARE_METATYPE(QMapbox::CoordinatesCollection);
Q_DECLARE_METATYPE(QMapbox::CoordinatesCollections);
Q_DECLARE_METATYPE(QMapbox::Feature);
Q_DECLARE_METATYPE(QMapbox::SymbolAnnotation);
Q_DECLARE_METATYPE(QMapbox::ShapeAnnotationGeometry);
Q_DECLARE_METATYPE(QMapbox::LineAnnotation);
Q_DECLARE_METATYPE(QMapbox::FillAnnotation);
#endif // QMAPBOX_H

@ -1,277 +0,0 @@
#ifndef QMAPBOXGL_H
#define QMAPBOXGL_H
#include <QImage>
#include <QMapbox>
#include <QMargins>
#include <QObject>
#include <QPointF>
#include <QSize>
#include <QString>
#include <QStringList>
#include <functional>
class QMapboxGLPrivate;
// This header follows the Qt coding style: https://wiki.qt.io/Qt_Coding_Style
class Q_MAPBOXGL_EXPORT QMapboxGLSettings
{
public:
QMapboxGLSettings();
enum GLContextMode {
UniqueGLContext = 0,
SharedGLContext
};
enum MapMode {
Continuous = 0,
Static
};
enum ConstrainMode {
NoConstrain = 0,
ConstrainHeightOnly,
ConstrainWidthAndHeight
};
enum ViewportMode {
DefaultViewport = 0,
FlippedYViewport
};
GLContextMode contextMode() const;
void setContextMode(GLContextMode);
MapMode mapMode() const;
void setMapMode(MapMode);
ConstrainMode constrainMode() const;
void setConstrainMode(ConstrainMode);
ViewportMode viewportMode() const;
void setViewportMode(ViewportMode);
unsigned cacheDatabaseMaximumSize() const;
void setCacheDatabaseMaximumSize(unsigned);
QString cacheDatabasePath() const;
void setCacheDatabasePath(const QString &);
QString assetPath() const;
void setAssetPath(const QString &);
QString accessToken() const;
void setAccessToken(const QString &);
QString apiBaseUrl() const;
void setApiBaseUrl(const QString &);
QString localFontFamily() const;
void setLocalFontFamily(const QString &);
std::function<std::string(const std::string &)> resourceTransform() const;
void setResourceTransform(const std::function<std::string(const std::string &)> &);
private:
GLContextMode m_contextMode;
MapMode m_mapMode;
ConstrainMode m_constrainMode;
ViewportMode m_viewportMode;
unsigned m_cacheMaximumSize;
QString m_cacheDatabasePath;
QString m_assetPath;
QString m_accessToken;
QString m_apiBaseUrl;
QString m_localFontFamily;
std::function<std::string(const std::string &)> m_resourceTransform;
};
struct Q_MAPBOXGL_EXPORT QMapboxGLCameraOptions {
QVariant center; // Coordinate
QVariant anchor; // QPointF
QVariant zoom; // double
QVariant bearing; // double
QVariant pitch; // double
};
class Q_MAPBOXGL_EXPORT QMapboxGL : public QObject
{
Q_OBJECT
Q_PROPERTY(double latitude READ latitude WRITE setLatitude)
Q_PROPERTY(double longitude READ longitude WRITE setLongitude)
Q_PROPERTY(double zoom READ zoom WRITE setZoom)
Q_PROPERTY(double bearing READ bearing WRITE setBearing)
Q_PROPERTY(double pitch READ pitch WRITE setPitch)
Q_PROPERTY(QString styleJson READ styleJson WRITE setStyleJson)
Q_PROPERTY(QString styleUrl READ styleUrl WRITE setStyleUrl)
Q_PROPERTY(double scale READ scale WRITE setScale)
Q_PROPERTY(QMapbox::Coordinate coordinate READ coordinate WRITE setCoordinate)
Q_PROPERTY(QMargins margins READ margins WRITE setMargins)
public:
enum MapChange {
MapChangeRegionWillChange = 0,
MapChangeRegionWillChangeAnimated,
MapChangeRegionIsChanging,
MapChangeRegionDidChange,
MapChangeRegionDidChangeAnimated,
MapChangeWillStartLoadingMap,
MapChangeDidFinishLoadingMap,
MapChangeDidFailLoadingMap,
MapChangeWillStartRenderingFrame,
MapChangeDidFinishRenderingFrame,
MapChangeDidFinishRenderingFrameFullyRendered,
MapChangeWillStartRenderingMap,
MapChangeDidFinishRenderingMap,
MapChangeDidFinishRenderingMapFullyRendered,
MapChangeDidFinishLoadingStyle,
MapChangeSourceDidChange
};
enum MapLoadingFailure {
StyleParseFailure,
StyleLoadFailure,
NotFoundFailure,
UnknownFailure
};
// Determines the orientation of the map.
enum NorthOrientation {
NorthUpwards, // Default
NorthRightwards,
NorthDownwards,
NorthLeftwards,
};
QMapboxGL(QObject* parent = 0,
const QMapboxGLSettings& = QMapboxGLSettings(),
const QSize& size = QSize(),
qreal pixelRatio = 1);
virtual ~QMapboxGL();
QString styleJson() const;
QString styleUrl() const;
void setStyleJson(const QString &);
void setStyleUrl(const QString &);
double latitude() const;
void setLatitude(double latitude);
double longitude() const;
void setLongitude(double longitude);
double scale() const;
void setScale(double scale, const QPointF &center = QPointF());
double zoom() const;
void setZoom(double zoom);
double minimumZoom() const;
double maximumZoom() const;
double bearing() const;
void setBearing(double degrees);
void setBearing(double degrees, const QPointF &center);
double pitch() const;
void setPitch(double pitch);
void pitchBy(double pitch);
NorthOrientation northOrientation() const;
void setNorthOrientation(NorthOrientation);
QMapbox::Coordinate coordinate() const;
void setCoordinate(const QMapbox::Coordinate &);
void setCoordinateZoom(const QMapbox::Coordinate &, double zoom);
void jumpTo(const QMapboxGLCameraOptions&);
void setGestureInProgress(bool inProgress);
void setTransitionOptions(qint64 duration, qint64 delay = 0);
void addAnnotationIcon(const QString &name, const QImage &sprite);
QMapbox::AnnotationID addAnnotation(const QMapbox::Annotation &);
void updateAnnotation(QMapbox::AnnotationID, const QMapbox::Annotation &);
void removeAnnotation(QMapbox::AnnotationID);
bool setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
bool setPaintProperty(const QString &layer, const QString &property, const QVariant &value);
bool isFullyLoaded() const;
void moveBy(const QPointF &offset);
void scaleBy(double scale, const QPointF &center = QPointF());
void rotateBy(const QPointF &first, const QPointF &second);
void resize(const QSize &size);
double metersPerPixelAtLatitude(double latitude, double zoom) const;
QMapbox::ProjectedMeters projectedMetersForCoordinate(const QMapbox::Coordinate &) const;
QMapbox::Coordinate coordinateForProjectedMeters(const QMapbox::ProjectedMeters &) const;
QPointF pixelForCoordinate(const QMapbox::Coordinate &) const;
QMapbox::Coordinate coordinateForPixel(const QPointF &) const;
QMapbox::CoordinateZoom coordinateZoomForBounds(const QMapbox::Coordinate &sw, QMapbox::Coordinate &ne) const;
QMapbox::CoordinateZoom coordinateZoomForBounds(const QMapbox::Coordinate &sw, QMapbox::Coordinate &ne, double bearing, double pitch);
void setMargins(const QMargins &margins);
QMargins margins() const;
void addSource(const QString &sourceID, const QVariantMap& params);
bool sourceExists(const QString &sourceID);
void updateSource(const QString &sourceID, const QVariantMap& params);
void removeSource(const QString &sourceID);
void addImage(const QString &name, const QImage &sprite);
void removeImage(const QString &name);
void addCustomLayer(const QString &id,
QScopedPointer<QMapbox::CustomLayerHostInterface>& host,
const QString& before = QString());
void addLayer(const QVariantMap &params, const QString& before = QString());
bool layerExists(const QString &id);
void removeLayer(const QString &id);
QVector<QString> layerIds() const;
void setFilter(const QString &layer, const QVariant &filter);
QVariant getFilter(const QString &layer) const;
// When rendering on a different thread,
// should be called on the render thread.
void createRenderer();
void destroyRenderer();
void setFramebufferObject(quint32 fbo, const QSize &size);
public slots:
void render();
void connectionEstablished();
// Commit changes, load all the resources
// and renders the map when completed.
void startStaticRender();
signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
void mapLoadingFailed(QMapboxGL::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
void staticRenderFinished(const QString &error);
private:
Q_DISABLE_COPY(QMapboxGL)
QMapboxGLPrivate *d_ptr;
};
Q_DECLARE_METATYPE(QMapboxGL::MapChange);
Q_DECLARE_METATYPE(QMapboxGL::MapLoadingFailure);
#endif // QMAPBOXGL_H

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ee37b571a5a50d07f2fd1a3150aa2842f10576e96e01278bbc060815549d57e9
size 10219704

@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
ARCHNAME="x86_64"
MAPLIBRE_FLAGS="-DMLN_QT_WITH_LOCATION=OFF"
if [ -f /AGNOS ]; then
ARCHNAME="larch64"
#MAPLIBRE_FLAGS="$MAPLIBRE_FLAGS -DCMAKE_SYSTEM_NAME=Android -DANDROID_ABI=arm64-v8a"
fi
cd $DIR
if [ ! -d maplibre ]; then
git clone git@github.com:maplibre/maplibre-native-qt.git $DIR/maplibre
fi
cd maplibre
git fetch --all
git checkout 3726266e127c1f94ad64837c9dbe03d238255816
git submodule update --depth=1 --recursive --init
# build
mkdir -p build
cd build
set -x
cmake $MAPLIBRE_FLAGS $DIR/maplibre
make -j$(nproc) || make -j2 || make -j1
INSTALL_DIR="$DIR/$ARCHNAME"
rm -rf $INSTALL_DIR
mkdir -p $INSTALL_DIR
rm -rf $INSTALL_DIR/lib $DIR/include
mkdir -p $INSTALL_DIR/lib $INSTALL_DIR/include $DIR/include
cp -r $DIR/maplibre/build/src/core/*.so* $INSTALL_DIR/lib
cp -r $DIR/maplibre/build/src/core/include/* $INSTALL_DIR/include
cp -r $DIR/maplibre/src/**/*.hpp $DIR/include

@ -0,0 +1,241 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2018 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "geojson_p.hpp"
#include "types.hpp"
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion_impl.hpp>
#include <QtCore/QVariant>
#include <QtGui/QColor>
#include <optional>
namespace mbgl::style::conversion {
std::string convertColor(const QColor &color);
template <>
class ConversionTraits<QVariant> {
public:
static bool isUndefined(const QVariant &value) { return value.isNull() || !value.isValid(); }
static bool isArray(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
return QMetaType::canConvert(value.metaType(), QMetaType(QMetaType::QVariantList));
#else
return value.canConvert(QVariant::List);
#endif
}
static std::size_t arrayLength(const QVariant &value) { return value.toList().size(); }
static QVariant arrayMember(const QVariant &value, std::size_t i) { return value.toList()[static_cast<int>(i)]; }
static bool isObject(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
return QMetaType::canConvert(value.metaType(), QMetaType(QMetaType::QVariantMap)) ||
value.typeId() == QMetaType::QByteArray
#else
return value.canConvert(QVariant::Map) || value.type() == QVariant::ByteArray
#endif
|| QString(value.typeName()) == QStringLiteral("QMapLibre::Feature") ||
value.userType() == qMetaTypeId<QVector<QMapLibre::Feature>>() ||
value.userType() == qMetaTypeId<QList<QMapLibre::Feature>>() ||
value.userType() == qMetaTypeId<std::list<QMapLibre::Feature>>();
}
static std::optional<QVariant> objectMember(const QVariant &value, const char *key) {
auto map = value.toMap();
auto iter = map.constFind(key);
if (iter != map.constEnd()) {
return iter.value();
}
return {};
}
template <class Fn>
static std::optional<Error> eachMember(const QVariant &value, Fn &&fn) {
auto map = value.toMap();
auto iter = map.constBegin();
while (iter != map.constEnd()) {
std::optional<Error> result = fn(iter.key().toStdString(), QVariant(iter.value()));
if (result) {
return result;
}
++iter;
}
return {};
}
static std::optional<bool> toBool(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() == QMetaType::Bool) {
#else
if (value.type() == QVariant::Bool) {
#endif
return value.toBool();
}
return {};
}
static std::optional<float> toNumber(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() == QMetaType::Int || value.typeId() == QMetaType::Double ||
value.typeId() == QMetaType::Long || value.typeId() == QMetaType::LongLong ||
value.typeId() == QMetaType::ULong || value.typeId() == QMetaType::ULongLong) {
#else
if (value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong ||
value.type() == QVariant::ULongLong) {
#endif
return value.toFloat();
}
return {};
}
static std::optional<double> toDouble(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() == QMetaType::Int || value.typeId() == QMetaType::Double ||
value.typeId() == QMetaType::Long || value.typeId() == QMetaType::LongLong ||
value.typeId() == QMetaType::ULong || value.typeId() == QMetaType::ULongLong) {
#else
if (value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong ||
value.type() == QVariant::ULongLong) {
#endif
return value.toDouble();
}
return {};
}
static std::optional<std::string> toString(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() == QMetaType::QString) {
return value.toString().toStdString();
}
if (value.typeId() == QMetaType::QColor) {
return convertColor(value.value<QColor>());
}
#else
if (value.type() == QVariant::String) {
return value.toString().toStdString();
}
if (value.type() == QVariant::Color) {
return convertColor(value.value<QColor>());
}
#endif
return {};
}
static std::optional<Value> toValue(const QVariant &value) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() == QMetaType::Bool) {
return {value.toBool()};
}
if (value.typeId() == QMetaType::QString) {
return {value.toString().toStdString()};
}
if (value.typeId() == QMetaType::QColor) {
return {convertColor(value.value<QColor>())};
}
if (value.typeId() == QMetaType::Int) {
return {static_cast<int64_t>(value.toInt())};
}
if (QMetaType::canConvert(value.metaType(), QMetaType(QMetaType::Double))) {
return {value.toDouble()};
}
#else
if (value.type() == QVariant::Bool) {
return {value.toBool()};
}
if (value.type() == QVariant::String) {
return {value.toString().toStdString()};
}
if (value.type() == QVariant::Color) {
return {convertColor(value.value<QColor>())};
}
if (value.type() == QVariant::Int) {
return {static_cast<int64_t>(value.toInt())};
}
if (value.canConvert(QVariant::Double)) {
return {value.toDouble()};
}
#endif
return {};
}
static std::optional<GeoJSON> toGeoJSON(const QVariant &value, Error &error) {
if (value.typeName() == QStringLiteral("QMapLibre::Feature")) {
return GeoJSON{QMapLibre::GeoJSON::asFeature(value.value<QMapLibre::Feature>())};
}
if (value.userType() == qMetaTypeId<QVector<QMapLibre::Feature>>()) {
return featureCollectionToGeoJSON(value.value<QVector<QMapLibre::Feature>>());
}
if (value.userType() == qMetaTypeId<QList<QMapLibre::Feature>>()) {
return featureCollectionToGeoJSON(value.value<QList<QMapLibre::Feature>>());
}
if (value.userType() == qMetaTypeId<std::list<QMapLibre::Feature>>()) {
return featureCollectionToGeoJSON(value.value<std::list<QMapLibre::Feature>>());
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (value.typeId() != QMetaType::QByteArray) {
#else
if (value.type() != QVariant::ByteArray) {
#endif
error = {"JSON data must be in QByteArray"};
return {};
}
const QByteArray data = value.toByteArray();
return parseGeoJSON(std::string(data.constData(), data.size()), error);
}
private:
template <typename T>
static GeoJSON featureCollectionToGeoJSON(const T &features) {
mapbox::feature::feature_collection<double> collection;
collection.reserve(static_cast<std::size_t>(features.size()));
for (const auto &feature : features) {
collection.push_back(QMapLibre::GeoJSON::asFeature(feature));
}
return GeoJSON{std::move(collection)};
}
};
template <class T, class... Args>
std::optional<T> convert(const QVariant &value, Error &error, Args &&...args) {
return convert<T>(Convertible(value), error, std::forward<Args>(args)...);
}
inline std::string convertColor(const QColor &color) {
return QString::asprintf("rgba(%d,%d,%d,%lf)", color.red(), color.green(), color.blue(), color.alphaF())
.toStdString();
}
} // namespace mbgl::style::conversion

@ -0,0 +1,20 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_CORE_EXPORT_H
#define QMAPLIBRE_CORE_EXPORT_H
#include <QtCore/QtGlobal>
#if !defined(QT_MAPLIBRE_STATIC)
#if defined(QT_BUILD_MAPLIBRE_CORE_LIB)
#define Q_MAPLIBRE_CORE_EXPORT Q_DECL_EXPORT
#else
#define Q_MAPLIBRE_CORE_EXPORT Q_DECL_IMPORT
#endif
#else
#define Q_MAPLIBRE_CORE_EXPORT
#endif
#endif // QMAPLIBRE_CORE_EXPORT_H

@ -0,0 +1,20 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_LOCATION_EXPORT_H
#define QMAPLIBRE_LOCATION_EXPORT_H
#include <QtCore/QtGlobal>
#if !defined(QT_MAPLIBRE_STATIC)
#if defined(QT_BUILD_MAPLIBRE_LOCATION_LIB)
#define Q_MAPLIBRE_LOCATION_EXPORT Q_DECL_EXPORT
#else
#define Q_MAPLIBRE_LOCATION_EXPORT Q_DECL_IMPORT
#endif
#else
#define Q_MAPLIBRE_LOCATION_EXPORT
#endif
#endif // QMAPLIBRE_LOCATION_EXPORT_H

@ -0,0 +1,20 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_WIDGETS_EXPORT_H
#define QMAPLIBRE_WIDGETS_EXPORT_H
#include <QtCore/QtGlobal>
#if !defined(QT_MAPLIBRE_STATIC)
#if defined(QT_BUILD_MAPLIBRE_WIDGETS_LIB)
#define Q_MAPLIBRE_WIDGETS_EXPORT Q_DECL_EXPORT
#else
#define Q_MAPLIBRE_WIDGETS_EXPORT Q_DECL_IMPORT
#endif
#else
#define Q_MAPLIBRE_WIDGETS_EXPORT
#endif
#endif // QMAPLIBRE_WIDGETS_EXPORT_H

@ -0,0 +1,30 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "types.hpp"
#include <mapbox/geojson.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/geometry.hpp>
#include <QtCore/QVariant>
#include <string>
namespace QMapLibre::GeoJSON {
mbgl::Point<double> asPoint(const Coordinate &coordinate);
mbgl::MultiPoint<double> asMultiPoint(const Coordinates &multiPoint);
mbgl::LineString<double> asLineString(const Coordinates &lineString);
mbgl::MultiLineString<double> asMultiLineString(const CoordinatesCollection &multiLineString);
mbgl::Polygon<double> asPolygon(const CoordinatesCollection &polygon);
mbgl::MultiPolygon<double> asMultiPolygon(const CoordinatesCollections &multiPolygon);
mbgl::Value asPropertyValue(const QVariant &value);
mbgl::FeatureIdentifier asFeatureIdentifier(const QVariant &id);
mbgl::GeoJSONFeature asFeature(const Feature &feature);
} // namespace QMapLibre::GeoJSON

@ -0,0 +1,56 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_GL_WIDGET_H
#define QMAPLIBRE_GL_WIDGET_H
#include <QMapLibreWidgets/Export>
#include <QMapLibre/Map>
#include <QMapLibre/Settings>
#include <QOpenGLWidget>
#include <memory>
QT_BEGIN_NAMESPACE
class QKeyEvent;
class QMouseEvent;
class QWheelEvent;
QT_END_NAMESPACE
namespace QMapLibre {
class GLWidgetPrivate;
class Q_MAPLIBRE_WIDGETS_EXPORT GLWidget : public QOpenGLWidget {
Q_OBJECT
public:
explicit GLWidget(const Settings &);
~GLWidget() override;
Map *map();
protected:
// QWidget implementation.
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
// Q{,Open}GLWidget implementation.
void initializeGL() override;
void paintGL() override;
private:
Q_DISABLE_COPY(GLWidget)
std::unique_ptr<GLWidgetPrivate> d_ptr;
};
} // namespace QMapLibre
#endif // QMAPLIBRE_GL_WIDGET_H

@ -0,0 +1,42 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include <QMapLibre/Map>
#include <QMapLibre/Settings>
#include <memory>
QT_BEGIN_NAMESPACE
class QKeyEvent;
class QMouseEvent;
class QWheelEvent;
QT_END_NAMESPACE
namespace QMapLibre {
class GLWidgetPrivate : public QObject {
Q_OBJECT
public:
explicit GLWidgetPrivate(QObject *parent, Settings settings);
~GLWidgetPrivate() override;
void handleMousePressEvent(QMouseEvent *event);
void handleMouseMoveEvent(QMouseEvent *event);
void handleWheelEvent(QWheelEvent *event) const;
std::unique_ptr<Map> m_map{};
Settings m_settings;
private:
Q_DISABLE_COPY(GLWidgetPrivate);
QPointF m_lastPos;
};
} // namespace QMapLibre

@ -0,0 +1,205 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_MAP_H
#define QMAPLIBRE_MAP_H
#include <QMapLibre/Export>
#include <QMapLibre/Settings>
#include <QMapLibre/Types>
#include <QtCore/QMargins>
#include <QtCore/QObject>
#include <QtCore/QPointF>
#include <QtCore/QSize>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtGui/QImage>
#include <functional>
#include <memory>
namespace QMapLibre {
class MapPrivate;
class Q_MAPLIBRE_CORE_EXPORT Map : public QObject {
Q_OBJECT
Q_PROPERTY(double latitude READ latitude WRITE setLatitude)
Q_PROPERTY(double longitude READ longitude WRITE setLongitude)
Q_PROPERTY(double zoom READ zoom WRITE setZoom)
Q_PROPERTY(double bearing READ bearing WRITE setBearing)
Q_PROPERTY(double pitch READ pitch WRITE setPitch)
Q_PROPERTY(QString styleJson READ styleJson WRITE setStyleJson)
Q_PROPERTY(QString styleUrl READ styleUrl WRITE setStyleUrl)
Q_PROPERTY(double scale READ scale WRITE setScale)
Q_PROPERTY(QMapLibre::Coordinate coordinate READ coordinate WRITE setCoordinate)
Q_PROPERTY(QMargins margins READ margins WRITE setMargins)
public:
enum MapChange {
MapChangeRegionWillChange = 0,
MapChangeRegionWillChangeAnimated,
MapChangeRegionIsChanging,
MapChangeRegionDidChange,
MapChangeRegionDidChangeAnimated,
MapChangeWillStartLoadingMap,
MapChangeDidFinishLoadingMap,
MapChangeDidFailLoadingMap,
MapChangeWillStartRenderingFrame,
MapChangeDidFinishRenderingFrame,
MapChangeDidFinishRenderingFrameFullyRendered,
MapChangeWillStartRenderingMap,
MapChangeDidFinishRenderingMap,
MapChangeDidFinishRenderingMapFullyRendered,
MapChangeDidFinishLoadingStyle,
MapChangeSourceDidChange
};
enum MapLoadingFailure {
StyleParseFailure,
StyleLoadFailure,
NotFoundFailure,
UnknownFailure
};
// Determines the orientation of the map.
enum NorthOrientation {
NorthUpwards, // Default
NorthRightwards,
NorthDownwards,
NorthLeftwards,
};
explicit Map(QObject *parent = nullptr,
const Settings &settings = Settings(),
const QSize &size = QSize(),
qreal pixelRatio = 1);
~Map() override;
[[nodiscard]] QString styleJson() const;
[[nodiscard]] QString styleUrl() const;
void setStyleJson(const QString &);
void setStyleUrl(const QString &);
[[nodiscard]] double latitude() const;
void setLatitude(double latitude);
[[nodiscard]] double longitude() const;
void setLongitude(double longitude);
[[nodiscard]] double scale() const;
void setScale(double scale, const QPointF &center = QPointF());
[[nodiscard]] double zoom() const;
void setZoom(double zoom);
[[nodiscard]] double minimumZoom() const;
[[nodiscard]] double maximumZoom() const;
[[nodiscard]] double bearing() const;
void setBearing(double degrees);
void setBearing(double degrees, const QPointF &center);
[[nodiscard]] double pitch() const;
void setPitch(double pitch);
void pitchBy(double pitch);
[[nodiscard]] NorthOrientation northOrientation() const;
void setNorthOrientation(NorthOrientation);
[[nodiscard]] Coordinate coordinate() const;
void setCoordinate(const Coordinate &coordinate);
void setCoordinateZoom(const Coordinate &coordinate, double zoom);
void jumpTo(const CameraOptions &);
void setGestureInProgress(bool inProgress);
void setTransitionOptions(qint64 duration, qint64 delay = 0);
void addAnnotationIcon(const QString &name, const QImage &sprite);
AnnotationID addAnnotation(const Annotation &annotation);
void updateAnnotation(AnnotationID id, const Annotation &annotation);
void removeAnnotation(AnnotationID id);
bool setLayoutProperty(const QString &layerId, const QString &propertyName, const QVariant &value);
bool setPaintProperty(const QString &layerId, const QString &propertyName, const QVariant &value);
[[nodiscard]] bool isFullyLoaded() const;
void moveBy(const QPointF &offset);
void scaleBy(double scale, const QPointF &center = QPointF());
void rotateBy(const QPointF &first, const QPointF &second);
void resize(const QSize &size);
[[nodiscard]] QPointF pixelForCoordinate(const Coordinate &coordinate) const;
[[nodiscard]] Coordinate coordinateForPixel(const QPointF &pixel) const;
[[nodiscard]] CoordinateZoom coordinateZoomForBounds(const Coordinate &sw, const Coordinate &ne) const;
[[nodiscard]] CoordinateZoom coordinateZoomForBounds(const Coordinate &sw,
const Coordinate &ne,
double bearing,
double pitch);
void setMargins(const QMargins &margins);
[[nodiscard]] QMargins margins() const;
void addSource(const QString &id, const QVariantMap &params);
bool sourceExists(const QString &id);
void updateSource(const QString &id, const QVariantMap &params);
void removeSource(const QString &id);
void addImage(const QString &id, const QImage &sprite);
void removeImage(const QString &id);
void addCustomLayer(const QString &id,
std::unique_ptr<CustomLayerHostInterface> host,
const QString &before = QString());
void addLayer(const QString &id, const QVariantMap &params, const QString &before = QString());
bool layerExists(const QString &id);
void removeLayer(const QString &id);
[[nodiscard]] QVector<QString> layerIds() const;
void setFilter(const QString &layerId, const QVariant &filter);
[[nodiscard]] QVariant getFilter(const QString &layerId) const;
// When rendering on a different thread,
// should be called on the render thread.
void createRenderer();
void destroyRenderer();
void setFramebufferObject(quint32 fbo, const QSize &size);
public slots:
void render();
void setConnectionEstablished();
// Commit changes, load all the resources
// and renders the map when completed.
void startStaticRender();
signals:
void needsRendering();
void mapChanged(Map::MapChange);
void mapLoadingFailed(Map::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
void staticRenderFinished(const QString &error);
private:
Q_DISABLE_COPY(Map)
std::unique_ptr<MapPrivate> d_ptr;
};
} // namespace QMapLibre
Q_DECLARE_METATYPE(QMapLibre::Map::MapChange);
Q_DECLARE_METATYPE(QMapLibre::Map::MapLoadingFailure);
#endif // QMAPLIBRE_MAP_H

@ -0,0 +1,54 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "map.hpp"
#include <mbgl/map/map_observer.hpp>
#include <mbgl/style/style.hpp>
#include <QtCore/QObject>
#include <exception>
#include <memory>
namespace QMapLibre {
class MapPrivate;
class MapObserver : public QObject, public mbgl::MapObserver {
Q_OBJECT
public:
explicit MapObserver(MapPrivate *ptr);
~MapObserver() override;
// mbgl::MapObserver implementation.
void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) final;
void onCameraIsChanging() final;
void onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) final;
void onWillStartLoadingMap() final;
void onDidFinishLoadingMap() final;
void onDidFailLoadingMap(mbgl::MapLoadError error, const std::string &what) final;
void onWillStartRenderingFrame() final;
void onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus status) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) final;
void onDidFinishLoadingStyle() final;
void onSourceChanged(mbgl::style::Source &source) final;
signals:
void mapChanged(Map::MapChange);
void mapLoadingFailed(Map::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
private:
Q_DISABLE_COPY(MapObserver)
MapPrivate *d_ptrRef;
};
} // namespace QMapLibre

@ -0,0 +1,79 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "map.hpp"
#include "map_observer_p.hpp"
#include "map_renderer_p.hpp"
#include <mbgl/actor/actor.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/renderer/renderer_frontend.hpp>
#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/geo.hpp>
#include <QtCore/QObject>
#include <QtCore/QSize>
#include <atomic>
#include <memory>
namespace QMapLibre {
class MapPrivate : public QObject, public mbgl::RendererFrontend {
Q_OBJECT
public:
explicit MapPrivate(Map *map, const Settings &settings, const QSize &size, qreal pixelRatio);
~MapPrivate() override;
// mbgl::RendererFrontend implementation.
void reset() final {}
void setObserver(mbgl::RendererObserver &observer) final;
void update(std::shared_ptr<mbgl::UpdateParameters> parameters) final;
// These need to be called on the same thread.
void createRenderer();
void destroyRenderer();
void render();
void setFramebufferObject(quint32 fbo, const QSize &size);
using PropertySetter = std::optional<mbgl::style::conversion::Error> (mbgl::style::Layer::*)(
const std::string &, const mbgl::style::conversion::Convertible &);
[[nodiscard]] bool setProperty(const PropertySetter &setter,
const QString &layerId,
const QString &name,
const QVariant &value) const;
mbgl::EdgeInsets margins;
std::unique_ptr<mbgl::Map> mapObj{};
public slots:
void requestRendering();
signals:
void needsRendering();
private:
Q_DISABLE_COPY(MapPrivate)
std::recursive_mutex m_mapRendererMutex;
std::shared_ptr<mbgl::RendererObserver> m_rendererObserver{};
std::shared_ptr<mbgl::UpdateParameters> m_updateParameters{};
std::unique_ptr<MapObserver> m_mapObserver{};
std::unique_ptr<MapRenderer> m_mapRenderer{};
std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform::TransformCallback>> m_resourceTransform{};
Settings::GLContextMode m_mode;
qreal m_pixelRatio;
QString m_localFontFamily;
std::atomic_flag m_renderQueued = ATOMIC_FLAG_INIT;
};
} // namespace QMapLibre

@ -0,0 +1,63 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "settings.hpp"
#include "utils/renderer_backend.hpp"
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/renderer/renderer_observer.hpp>
#include <mbgl/util/util.hpp>
#include <QtCore/QObject>
#include <QtGlobal>
#include <memory>
#include <mutex>
namespace mbgl {
class Renderer;
class UpdateParameters;
} // namespace mbgl
namespace QMapLibre {
class RendererBackend;
class MapRenderer : public QObject {
Q_OBJECT
public:
MapRenderer(qreal pixelRatio, Settings::GLContextMode, const QString &localFontFamily);
~MapRenderer() override;
void render();
void updateFramebuffer(quint32 fbo, const mbgl::Size &size);
void setObserver(mbgl::RendererObserver *observer);
// Thread-safe, called by the Frontend
void updateParameters(std::shared_ptr<mbgl::UpdateParameters> parameters);
signals:
void needsRendering();
private:
MBGL_STORE_THREAD(tid)
Q_DISABLE_COPY(MapRenderer)
std::mutex m_updateMutex;
std::shared_ptr<mbgl::UpdateParameters> m_updateParameters;
RendererBackend m_backend;
std::unique_ptr<mbgl::Renderer> m_renderer{};
bool m_forceScheduler{};
};
} // namespace QMapLibre

@ -0,0 +1,54 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2017 Mapbox, Inc.
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include "export_location.hpp"
#include <QMapLibre/Map>
#include <QMapLibre/StyleParameter>
#include <QtLocation/private/qgeomap_p.h>
namespace QMapLibre {
class QGeoMapMapLibrePrivate;
class Q_MAPLIBRE_LOCATION_EXPORT QGeoMapMapLibre : public QGeoMap {
Q_OBJECT
Q_DECLARE_PRIVATE(QGeoMapMapLibre)
public:
explicit QGeoMapMapLibre(QGeoMappingManagerEngine *engine, QObject *parent = nullptr);
~QGeoMapMapLibre() override;
[[nodiscard]] Capabilities capabilities() const override;
void setSettings(const Settings &settings);
void setMapItemsBefore(const QString &mapItemsBefore);
void addStyleParameter(StyleParameter *parameter);
void removeStyleParameter(StyleParameter *parameter);
void clearStyleParameters();
private Q_SLOTS:
// QMapLibre
void onMapChanged(Map::MapChange);
// QDeclarativeGeoMapItemBase
void onMapItemPropertyChanged();
void onMapItemSubPropertyChanged();
void onMapItemUnsupportedPropertyChanged();
void onMapItemGeometryChanged();
// StyleParameter
void onStyleParameterUpdated(StyleParameter *parameter);
private:
QSGNode *updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) override;
};
} // namespace QMapLibre

@ -0,0 +1,93 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2017 Mapbox, Inc.
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include "qgeomap.hpp"
#include <QMapLibre/Settings>
#include <QMapLibre/StyleParameter>
#include <QtLocation/private/qgeomap_p_p.h>
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QRectF>
#include <QtCore/QSharedPointer>
#include <QtCore/QTimer>
#include <QtCore/QVariant>
namespace QMapLibre {
class Map;
class StyleChange;
class QGeoMapMapLibrePrivate : public QGeoMapPrivate {
Q_DECLARE_PUBLIC(QGeoMapMapLibre)
public:
explicit QGeoMapMapLibrePrivate(QGeoMappingManagerEngine *engine);
~QGeoMapMapLibrePrivate() override;
QSGNode *updateSceneGraph(QSGNode *oldNode, QQuickWindow *window);
QGeoMap::ItemTypes supportedMapItemTypes() const override;
void addMapItem(QDeclarativeGeoMapItemBase *item) override;
void removeMapItem(QDeclarativeGeoMapItemBase *item) override;
void addStyleParameter(StyleParameter *parameter);
void removeStyleParameter(StyleParameter *parameter);
void clearStyleParameters();
/* Data members */
enum SyncState : int {
NoSync = 0,
ViewportSync = 1 << 0,
CameraDataSync = 1 << 1,
MapTypeSync = 1 << 2,
VisibleAreaSync = 1 << 3
};
Q_DECLARE_FLAGS(SyncStates, SyncState);
Settings m_settings;
QString m_mapItemsBefore;
QList<StyleParameter *> m_mapParameters;
QTimer m_refresh;
bool m_shouldRefresh = true;
bool m_warned = false;
bool m_threadedRendering = false;
bool m_styleLoaded = false;
SyncStates m_syncState = NoSync;
std::vector<std::unique_ptr<StyleChange>> m_styleChanges;
protected:
void changeViewportSize(const QSize &size) override;
void changeCameraData(const QGeoCameraData &data) override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
void changeActiveMapType(const QGeoMapType &mapType) override;
#else
void changeActiveMapType(const QGeoMapType mapType) override;
#endif
void setVisibleArea(const QRectF &visibleArea) override;
QRectF visibleArea() const override;
private:
Q_DISABLE_COPY(QGeoMapMapLibrePrivate);
void syncStyleChanges(Map *map);
void threadedRenderingHack(QQuickWindow *window, Map *map);
QRectF m_visibleArea;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMapMapLibrePrivate::SyncStates)
} // namespace QMapLibre

@ -0,0 +1,9 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#include "export_core.hpp"
#include "map.hpp"
#include "settings.hpp"
#include "types.hpp"
#include "utils.hpp"

@ -0,0 +1,6 @@
// Copyright (C) 2023 MapLibre contributors
// SPDX-License-Identifier: BSD-2-Clause
#include "export_widgets.hpp"
#include "gl_widget.hpp"

@ -0,0 +1,31 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2017 Mapbox, Inc.
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include "export_location.hpp"
#include <QMapLibre/Settings>
#include <QtLocation/private/qgeomappingmanagerengine_p.h>
#include <QtLocation/QGeoServiceProvider>
namespace QMapLibre {
class Q_MAPLIBRE_LOCATION_EXPORT QtMappingEngine : public QGeoMappingManagerEngine {
Q_OBJECT
public:
QtMappingEngine(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString);
QGeoMap *createMap() override;
private:
Settings m_settings;
QString m_mapItemsBefore;
};
} // namespace QMapLibre

@ -0,0 +1,125 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_SETTINGS_H
#define QMAPLIBRE_SETTINGS_H
#include <QMapLibre/Export>
#include <QMapLibre/Types>
#include <QtCore/QString>
#include <QtGui/QImage>
#include <functional>
#include <memory>
// TODO: this will be wrapped at some point
namespace mbgl {
class TileServerOptions;
} // namespace mbgl
namespace QMapLibre {
class SettingsPrivate;
class Q_MAPLIBRE_CORE_EXPORT Settings {
public:
enum GLContextMode : bool {
UniqueGLContext,
SharedGLContext
};
enum MapMode {
Continuous = 0,
Static
};
enum ConstrainMode {
NoConstrain = 0,
ConstrainHeightOnly,
ConstrainWidthAndHeight
};
enum ViewportMode {
DefaultViewport = 0,
FlippedYViewport
};
enum ProviderTemplate {
NoProvider = 0,
MapLibreProvider,
MapTilerProvider,
MapboxProvider
};
using ResourceTransformFunction = std::function<std::string(const std::string &)>;
explicit Settings(ProviderTemplate provider = NoProvider);
~Settings();
Settings(const Settings &s);
Settings(Settings &&s) noexcept;
Settings &operator=(const Settings &s);
Settings &operator=(Settings &&s) noexcept;
[[nodiscard]] GLContextMode contextMode() const;
void setContextMode(GLContextMode);
[[nodiscard]] MapMode mapMode() const;
void setMapMode(MapMode);
[[nodiscard]] ConstrainMode constrainMode() const;
void setConstrainMode(ConstrainMode);
[[nodiscard]] ViewportMode viewportMode() const;
void setViewportMode(ViewportMode);
[[nodiscard]] unsigned cacheDatabaseMaximumSize() const;
void setCacheDatabaseMaximumSize(unsigned);
[[nodiscard]] QString cacheDatabasePath() const;
void setCacheDatabasePath(const QString &path);
[[nodiscard]] QString assetPath() const;
void setAssetPath(const QString &path);
[[nodiscard]] QString apiKey() const;
void setApiKey(const QString &key);
[[nodiscard]] QString apiBaseUrl() const;
void setApiBaseUrl(const QString &url);
[[nodiscard]] QString localFontFamily() const;
void setLocalFontFamily(const QString &family);
[[nodiscard]] QString clientName() const;
void setClientName(const QString &name);
[[nodiscard]] QString clientVersion() const;
void setClientVersion(const QString &version);
[[nodiscard]] ResourceTransformFunction resourceTransform() const;
void setResourceTransform(const ResourceTransformFunction &transform);
void setProviderTemplate(ProviderTemplate providerTemplate);
void setStyles(const Styles &styles);
[[nodiscard]] const Styles &styles() const;
[[nodiscard]] Styles providerStyles() const;
[[nodiscard]] Coordinate defaultCoordinate() const;
void setDefaultCoordinate(const Coordinate &coordinate);
[[nodiscard]] double defaultZoom() const;
void setDefaultZoom(double zoom);
[[nodiscard]] bool customTileServerOptions() const;
[[nodiscard]] const mbgl::TileServerOptions &tileServerOptions() const;
private:
std::unique_ptr<SettingsPrivate> d_ptr;
};
} // namespace QMapLibre
#endif // QMAPLIBRE_SETTINGS_H

@ -0,0 +1,57 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include "settings.hpp"
#include "types.hpp"
#include <mbgl/util/tile_server_options.hpp>
#include <QtCore/QString>
#include <QtCore/QVector>
#include <functional>
#include <memory>
namespace mbgl {
class TileServerOptions;
} // namespace mbgl
namespace QMapLibre {
class SettingsPrivate {
public:
SettingsPrivate();
void setProviderTemplate(Settings::ProviderTemplate providerTemplate);
void setProviderApiBaseUrl(const QString &url);
Settings::GLContextMode m_contextMode{Settings::SharedGLContext};
Settings::MapMode m_mapMode{Settings::Continuous};
Settings::ConstrainMode m_constrainMode{Settings::ConstrainHeightOnly};
Settings::ViewportMode m_viewportMode{Settings::DefaultViewport};
Settings::ProviderTemplate m_providerTemplate{Settings::NoProvider};
unsigned m_cacheMaximumSize;
QString m_cacheDatabasePath;
QString m_assetPath;
QString m_apiKey;
QString m_localFontFamily;
QString m_clientName;
QString m_clientVersion;
Coordinate m_defaultCoordinate{};
double m_defaultZoom{};
Styles m_styles;
std::function<std::string(const std::string &)> m_resourceTransform;
bool m_customTileServerOptions{};
mbgl::TileServerOptions m_tileServerOptions{};
};
} // namespace QMapLibre

@ -0,0 +1,34 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2017 Mapbox, Inc.
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include <QMapLibre/Types>
#include <QtLocation/private/qdeclarativecirclemapitem_p.h>
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
#include <QtLocation/private/qdeclarativerectanglemapitem_p.h>
namespace QMapLibre::StyleChangeUtils {
Feature featureFromMapRectangle(QDeclarativeRectangleMapItem *item);
Feature featureFromMapCircle(QDeclarativeCircleMapItem *item);
Feature featureFromMapPolygon(QDeclarativePolygonMapItem *item);
Feature featureFromMapPolyline(QDeclarativePolylineMapItem *item);
Feature featureFromMapItem(QDeclarativeGeoMapItemBase *item);
QString featureId(QDeclarativeGeoMapItemBase *item);
std::vector<FeatureProperty> featureLayoutPropertiesFromMapPolyline(QDeclarativePolylineMapItem *item);
std::vector<FeatureProperty> featureLayoutPropertiesFromMapItem(QDeclarativeGeoMapItemBase *item);
std::vector<FeatureProperty> featurePaintPropertiesFromMapRectangle(QDeclarativeRectangleMapItem *item);
std::vector<FeatureProperty> featurePaingPropertiesFromMapCircle(QDeclarativeCircleMapItem *item);
std::vector<FeatureProperty> featurePaintPropertiesFromMapPolygon(QDeclarativePolygonMapItem *item);
std::vector<FeatureProperty> featurePaintPropertiesFromMapPolyline(QDeclarativePolylineMapItem *item);
std::vector<FeatureProperty> featurePaintPropertiesFromMapItem(QDeclarativeGeoMapItemBase *item);
std::vector<FeatureProperty> featurePropertiesFromMapItem(QDeclarativeGeoMapItemBase *item);
} // namespace QMapLibre::StyleChangeUtils

@ -0,0 +1,42 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2017 Mapbox, Inc.
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include <QtQuick/QQuickWindow>
#include <QtQuick/QSGRenderNode>
#include <QtQuick/QSGSimpleTextureNode>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtOpenGL/QOpenGLFramebufferObject>
#else
#include <QtGui/QOpenGLFramebufferObject>
#endif
#include <QMapLibre/Map>
namespace QMapLibre {
class QGeoMapMapLibre;
class TextureNode : public QSGSimpleTextureNode {
public:
TextureNode(const Settings &setting, const QSize &size, qreal pixelRatio, QGeoMapMapLibre *geoMap);
[[nodiscard]] Map *map() const;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void resize(const QSize &size, qreal pixelRatio, QQuickWindow *window);
#else
void resize(const QSize &size, qreal pixelRatio);
#endif
void render(QQuickWindow *);
private:
std::unique_ptr<Map> m_map{};
std::unique_ptr<QOpenGLFramebufferObject> m_fbo{};
};
} // namespace QMapLibre

@ -0,0 +1,206 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_TYPES_H
#define QMAPLIBRE_TYPES_H
#include <QMapLibre/Export>
#include <QtCore/QPair>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtCore/QVector>
#include <QtGui/QColor>
#include <utility>
namespace QMapLibre {
using Coordinate = QPair<double, double>;
using CoordinateZoom = QPair<Coordinate, double>;
using ProjectedMeters = QPair<double, double>;
using Coordinates = QVector<Coordinate>;
using CoordinatesCollection = QVector<Coordinates>;
using CoordinatesCollections = QVector<CoordinatesCollection>;
struct Q_MAPLIBRE_CORE_EXPORT Style {
enum Type { // Taken from Qt to be in sync with QtLocation
NoMap = 0,
StreetMap,
SatelliteMapDay,
SatelliteMapNight,
TerrainMap,
HybridMap,
TransitMap,
GrayStreetMap,
PedestrianMap,
CarNavigationMap,
CycleMap,
CustomMap = 100
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
explicit Style(QString url_, QString name_ = QString())
: url(std::move(url_)),
name(std::move(name_)) {}
#else
explicit Style(QString url_ = QString(), QString name_ = QString())
: url(std::move(url_)),
name(std::move(name_)) {}
#endif
QString url;
QString name;
QString description;
bool night{};
Type type{CustomMap};
};
using Styles = QVector<Style>;
struct Q_MAPLIBRE_CORE_EXPORT Feature {
enum Type {
PointType = 1,
LineStringType,
PolygonType
};
/*! Class constructor. */
explicit Feature(Type type_ = PointType,
CoordinatesCollections geometry_ = CoordinatesCollections(),
QVariantMap properties_ = QVariantMap(),
QVariant id_ = QVariant())
: type(type_),
geometry(std::move(geometry_)),
properties(std::move(properties_)),
id(std::move(id_)) {}
Type type;
CoordinatesCollections geometry;
QVariantMap properties;
QVariant id;
};
struct Q_MAPLIBRE_CORE_EXPORT FeatureProperty {
enum Type {
LayoutProperty = 1,
PaintProperty,
};
/*! Class constructor. */
explicit FeatureProperty(Type type_, QString name_, QVariant value_)
: type(type_),
name(std::move(name_)),
value(std::move(value_)) {}
Type type;
QString name;
QVariant value;
};
struct Q_MAPLIBRE_CORE_EXPORT ShapeAnnotationGeometry {
enum Type {
LineStringType = 1,
PolygonType,
MultiLineStringType,
MultiPolygonType
};
/*! Class constructor. */
explicit ShapeAnnotationGeometry(Type type_ = LineStringType,
CoordinatesCollections geometry_ = CoordinatesCollections())
: type(type_),
geometry(std::move(geometry_)) {}
Type type;
CoordinatesCollections geometry;
};
struct Q_MAPLIBRE_CORE_EXPORT SymbolAnnotation {
Coordinate geometry;
QString icon;
};
struct Q_MAPLIBRE_CORE_EXPORT LineAnnotation {
/*! Class constructor. */
explicit LineAnnotation(ShapeAnnotationGeometry geometry_ = ShapeAnnotationGeometry(),
float opacity_ = 1.0f,
float width_ = 1.0f,
const QColor &color_ = Qt::black)
: geometry(std::move(geometry_)),
opacity(opacity_),
width(width_),
color(color_) {}
ShapeAnnotationGeometry geometry;
float opacity;
float width;
QColor color;
};
struct Q_MAPLIBRE_CORE_EXPORT FillAnnotation {
/*! Class constructor. */
explicit FillAnnotation(ShapeAnnotationGeometry geometry_ = ShapeAnnotationGeometry(),
float opacity_ = 1.0f,
const QColor &color_ = Qt::black,
QVariant outlineColor_ = QVariant())
: geometry(std::move(geometry_)),
opacity(opacity_),
color(color_),
outlineColor(std::move(outlineColor_)) {}
ShapeAnnotationGeometry geometry;
float opacity;
QColor color;
QVariant outlineColor;
};
using Annotation = QVariant;
using AnnotationID = quint32;
using AnnotationIDs = QVector<AnnotationID>;
struct Q_MAPLIBRE_CORE_EXPORT CameraOptions {
QVariant center; // Coordinate
QVariant anchor; // QPointF
QVariant zoom; // double
QVariant bearing; // double
QVariant pitch; // double
};
// This struct is a 1:1 copy of mbgl::CustomLayerRenderParameters.
struct Q_MAPLIBRE_CORE_EXPORT CustomLayerRenderParameters {
double width;
double height;
double latitude;
double longitude;
double zoom;
double bearing;
double pitch;
double fieldOfView;
};
class Q_MAPLIBRE_CORE_EXPORT CustomLayerHostInterface {
public:
virtual ~CustomLayerHostInterface() = default;
virtual void initialize() = 0;
virtual void render(const CustomLayerRenderParameters &) = 0;
virtual void deinitialize() = 0;
};
} // namespace QMapLibre
Q_DECLARE_METATYPE(QMapLibre::Coordinate);
Q_DECLARE_METATYPE(QMapLibre::Coordinates);
Q_DECLARE_METATYPE(QMapLibre::CoordinatesCollection);
Q_DECLARE_METATYPE(QMapLibre::CoordinatesCollections);
Q_DECLARE_METATYPE(QMapLibre::Feature);
Q_DECLARE_METATYPE(QMapLibre::SymbolAnnotation);
Q_DECLARE_METATYPE(QMapLibre::ShapeAnnotationGeometry);
Q_DECLARE_METATYPE(QMapLibre::LineAnnotation);
Q_DECLARE_METATYPE(QMapLibre::FillAnnotation);
#endif // QMAPLIBRE_TYPES_H

@ -0,0 +1,28 @@
// Copyright (C) 2023 MapLibre contributors
// Copyright (C) 2019 Mapbox, Inc.
// SPDX-License-Identifier: BSD-2-Clause
#ifndef QMAPLIBRE_UTILS_H
#define QMAPLIBRE_UTILS_H
#include <QMapLibre/Export>
#include <QMapLibre/Types>
namespace QMapLibre {
enum NetworkMode {
Online, // Default
Offline,
};
Q_MAPLIBRE_CORE_EXPORT NetworkMode networkMode();
Q_MAPLIBRE_CORE_EXPORT void setNetworkMode(NetworkMode mode);
Q_MAPLIBRE_CORE_EXPORT double metersPerPixelAtLatitude(double latitude, double zoom);
Q_MAPLIBRE_CORE_EXPORT ProjectedMeters projectedMetersForCoordinate(const Coordinate &coordinate);
Q_MAPLIBRE_CORE_EXPORT Coordinate coordinateForProjectedMeters(const ProjectedMeters &projectedMeters);
} // namespace QMapLibre
#endif // QMAPLIBRE_UTILS_H

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53ebf0802c8f5e581e7d99d743ea91271db531bfcdbddcf863760789f2962577
size 10205096

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53ebf0802c8f5e581e7d99d743ea91271db531bfcdbddcf863760789f2962577
size 10205096

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b718e4ea770105893dc41f64be36f806586a9471e2bb9d18d5ad97e906434548
size 11000296
Loading…
Cancel
Save