diff --git a/all/modules/core/DoubleVector.i b/all/modules/core/DoubleVector.i new file mode 100644 index 000000000..9b614c3a3 --- /dev/null +++ b/all/modules/core/DoubleVector.i @@ -0,0 +1,18 @@ +#ifndef _DOUBLEVECTOR_I +#define _DOUBLEVECTOR_I + +#pragma SWIG nowarn=302 + +%module DoubleVector + +%include + +!value_type(std::vector, core.DoubleVector) + +#ifdef SWIGOBJECTIVEC +%template(NTDoubleVector) std::vector; +#else +%template(DoubleVector) std::vector; +#endif + +#endif \ No newline at end of file diff --git a/all/modules/layers/HillshadeRasterTileLayer.i b/all/modules/layers/HillshadeRasterTileLayer.i index ea243b0a9..7ba5fc306 100644 --- a/all/modules/layers/HillshadeRasterTileLayer.i +++ b/all/modules/layers/HillshadeRasterTileLayer.i @@ -3,7 +3,7 @@ %module HillshadeRasterTileLayer -!proxy_imports(carto::HillshadeRasterTileLayer, datasources.TileDataSource, graphics.Color, layers.RasterTileLayer) +!proxy_imports(carto::HillshadeRasterTileLayer, core.MapPos, core.MapPosVector, core.DoubleVector, datasources.TileDataSource, rastertiles.ElevationDecoder, graphics.Color, layers.RasterTileLayer) %{ #include "layers/HillshadeRasterTileLayer.h" @@ -15,13 +15,17 @@ %include %import "datasources/TileDataSource.i" +%import "rastertiles/ElevationDecoder.i" %import "graphics/Color.i" %import "layers/RasterTileLayer.i" +%import "core/DoubleVector.i" !polymorphic_shared_ptr(carto::HillshadeRasterTileLayer, layers.HillshadeRasterTileLayer) %attribute(carto::HillshadeRasterTileLayer, float, Contrast, getContrast, setContrast) %attribute(carto::HillshadeRasterTileLayer, float, HeightScale, getHeightScale, setHeightScale) +%attribute(carto::HillshadeRasterTileLayer, float, IlluminationDirection, getIlluminationDirection, setIlluminationDirection) +%attribute(carto::HillshadeRasterTileLayer, bool, IlluminationMapRotationEnabled, getIlluminationMapRotationEnabled, setIlluminationMapRotationEnabled) %attributeval(carto::HillshadeRasterTileLayer, carto::Color, ShadowColor, getShadowColor, setShadowColor) %attributeval(carto::HillshadeRasterTileLayer, carto::Color, HighlightColor, getHighlightColor, setHighlightColor) %std_exceptions(carto::HillshadeRasterTileLayer::HillshadeRasterTileLayer) diff --git a/all/modules/rastertiles/ElevationDecoder.i b/all/modules/rastertiles/ElevationDecoder.i new file mode 100644 index 000000000..34a5dddf0 --- /dev/null +++ b/all/modules/rastertiles/ElevationDecoder.i @@ -0,0 +1,26 @@ +#ifndef _ELEVATIONDECODER_I +#define _ELEVATIONDECODER_I + +%module ElevationDecoder + +!proxy_imports(carto::ElevationDecoder, graphics.Color) + +%{ +#include "rastertiles/ElevationDecoder.h" +#include +%} + +%include +%include + +%import "graphics/Color.i" + +!polymorphic_shared_ptr(carto::ElevationDecoder, rastertiles.ElevationDecoder) + +!standard_equals(carto::ElevationDecoder); +%ignore carto::ElevationDecoder::getColorComponentCoefficients; +%ignore carto::ElevationDecoder::getVectorTileScales; + +%include "rastertiles/ElevationDecoder.h" + +#endif diff --git a/all/modules/rastertiles/MapBoxElevationDataDecoder.i b/all/modules/rastertiles/MapBoxElevationDataDecoder.i new file mode 100644 index 000000000..51f4c5584 --- /dev/null +++ b/all/modules/rastertiles/MapBoxElevationDataDecoder.i @@ -0,0 +1,30 @@ +#ifndef _MAPBOXELEVATIONDATADECODER_I +#define _MAPBOXELEVATIONDATADECODER_I + +%module MapBoxElevationDataDecoder + +%module(directors="1") MapBoxElevationDataDecoder +!proxy_imports(carto::MapBoxElevationDataDecoder, graphics.Color, core.MapPos, core.MapPosVector, datasources.TileDataSource, rastertiles.ElevationDecoder) + +%{ +#include "rastertiles/MapBoxElevationDataDecoder.h" +#include +%} + +%include +%include + +%import "graphics/Color.i" +%import "rastertiles/ElevationDecoder.i" + +!polymorphic_shared_ptr(carto::MapBoxElevationDataDecoder, rastertiles.MapBoxElevationDataDecoder) +!standard_equals(carto::MapBoxElevationDataDecoder); + +%feature("director") carto::MapBoxElevationDataDecoder; + +%ignore carto::MapBoxElevationDataDecoder::getColorComponentCoefficients; +%ignore carto::MapBoxElevationDataDecoder::getVectorTileScales; + +%include "rastertiles/MapBoxElevationDataDecoder.h" + +#endif diff --git a/all/modules/rastertiles/TerrariumElevationDataDecoder.i b/all/modules/rastertiles/TerrariumElevationDataDecoder.i new file mode 100644 index 000000000..bc42fb65a --- /dev/null +++ b/all/modules/rastertiles/TerrariumElevationDataDecoder.i @@ -0,0 +1,30 @@ +#ifndef _TERRARIUMELEVATIONDATADECODER_I +#define _TERRARIUMELEVATIONDATADECODER_I + +%module TerrariumElevationDataDecoder + +%module(directors="1") TerrariumElevationDataDecoder +!proxy_imports(carto::TerrariumElevationDataDecoder, graphics.Color, core.MapPos, core.MapPosVector, datasources.TileDataSource, rastertiles.ElevationDecoder) + +%{ +#include "rastertiles/TerrariumElevationDataDecoder.h" +#include +%} + +%include +%include + +%import "graphics/Color.i" +%import "rastertiles/ElevationDecoder.i" + +!polymorphic_shared_ptr(carto::TerrariumElevationDataDecoder, rastertiles.TerrariumElevationDataDecoder) +!standard_equals(carto::TerrariumElevationDataDecoder); + +%feature("director") carto::TerrariumElevationDataDecoder; + +%ignore carto::TerrariumElevationDataDecoder::getColorComponentCoefficients; +%ignore carto::TerrariumElevationDataDecoder::getVectorTileScales; + +%include "rastertiles/TerrariumElevationDataDecoder.h" + +#endif diff --git a/all/modules/routing/PackageManagerValhallaRoutingService.i b/all/modules/routing/PackageManagerValhallaRoutingService.i index 1f428359c..90a89559a 100644 --- a/all/modules/routing/PackageManagerValhallaRoutingService.i +++ b/all/modules/routing/PackageManagerValhallaRoutingService.i @@ -5,7 +5,7 @@ #if defined(_CARTO_ROUTING_SUPPORT) && defined(_CARTO_VALHALLA_ROUTING_SUPPORT) && defined(_CARTO_PACKAGEMANAGER_SUPPORT) -!proxy_imports(carto::PackageManagerValhallaRoutingService, packagemanager.PackageManager, core.Variant, routing.RoutingService, routing.RoutingRequest, routing.RoutingResult, routing.RouteMatchingRequest, routing.RouteMatchingResult) +!proxy_imports(carto::PackageManagerValhallaRoutingService, packagemanager.PackageManager, core.Variant, routing.RoutingService, routing.RoutingRequest, routing.RoutingResult, routing.RouteMatchingRequest, routing.RouteMatchingResult, datasources.TileDataSource, rastertiles.ElevationDecoder) %{ #include "routing/PackageManagerValhallaRoutingService.h" @@ -20,6 +20,8 @@ %import "core/Variant.i" %import "routing/RoutingService.i" %import "packagemanager/PackageManager.i" +%import "datasources/TileDataSource.i" +%import "rastertiles/ElevationDecoder.i" !polymorphic_shared_ptr(carto::PackageManagerValhallaRoutingService, routing.PackageManagerValhallaRoutingService) diff --git a/all/modules/routing/ValhallaOfflineRoutingService.i b/all/modules/routing/ValhallaOfflineRoutingService.i index 227dbf819..614ea0a43 100644 --- a/all/modules/routing/ValhallaOfflineRoutingService.i +++ b/all/modules/routing/ValhallaOfflineRoutingService.i @@ -5,7 +5,7 @@ #if defined(_CARTO_ROUTING_SUPPORT) && defined(_CARTO_VALHALLA_ROUTING_SUPPORT) && defined(_CARTO_OFFLINE_SUPPORT) -!proxy_imports(carto::ValhallaOfflineRoutingService, core.Variant, routing.RoutingService, routing.RoutingRequest, routing.RoutingResult, routing.RouteMatchingRequest, routing.RouteMatchingResult) +!proxy_imports(carto::ValhallaOfflineRoutingService, core.Variant, routing.RoutingService, routing.RoutingRequest, routing.RoutingResult, routing.RouteMatchingRequest, routing.RouteMatchingResult, datasources.TileDataSource, rastertiles.ElevationDecoder) %{ #include "routing/ValhallaOfflineRoutingService.h" @@ -19,6 +19,8 @@ %import "core/Variant.i" %import "routing/RoutingService.i" +%import "datasources/TileDataSource.i" +%import "rastertiles/ElevationDecoder.i" !polymorphic_shared_ptr(carto::ValhallaOfflineRoutingService, routing.ValhallaOfflineRoutingService) diff --git a/all/native/layers/HillshadeRasterTileLayer.cpp b/all/native/layers/HillshadeRasterTileLayer.cpp index d9236ae1d..40f5c4fc4 100644 --- a/all/native/layers/HillshadeRasterTileLayer.cpp +++ b/all/native/layers/HillshadeRasterTileLayer.cpp @@ -1,12 +1,17 @@ #include "HillshadeRasterTileLayer.h" -#include "graphics/Bitmap.h" #include "renderers/MapRenderer.h" #include "renderers/TileRenderer.h" #include "utils/Log.h" +#include "utils/TileUtils.h" +#include "core/BinaryData.h" +#include "projections/EPSG3857.h" +#include "projections/Projection.h" #include #include +#include "graphics/Bitmap.h" + #include #include #include @@ -14,27 +19,90 @@ #include #include #include +#include + +namespace { + + + + std::array readTileBitmapColor(const std::shared_ptr& bitmap, int x, int y) { + x = std::max(0, std::min(x, (int)bitmap->getWidth() - 1)); + y = bitmap->getHeight() - 1 - std::max(0, std::min(y, (int)bitmap->getHeight() - 1)); + + switch (bitmap->getColorFormat()) { + case carto::ColorFormat::COLOR_FORMAT_GRAYSCALE: + { + std::uint8_t val = bitmap->getPixelData()[y * bitmap->getWidth() + x]; + return std::array { { val, val, val, 255 } }; + } + case carto::ColorFormat::COLOR_FORMAT_RGB: + { + const std::uint8_t* valPtr = &bitmap->getPixelData()[(y * bitmap->getWidth() + x) * 3]; + return std::array { { valPtr[0], valPtr[1], valPtr[2], 255 } }; + } + case carto::ColorFormat::COLOR_FORMAT_RGBA: + { + const std::uint8_t* valPtr = &bitmap->getPixelData()[(y * bitmap->getWidth() + x) * 4]; + return std::array { { valPtr[0], valPtr[1], valPtr[2], valPtr[3] } }; + } + default: + break; + } + return std::array { { 0, 0, 0, 0 } }; + } + + std::array readTileBitmapColor(const std::shared_ptr& bitmap, float x, float y) { + std::array result { { 0, 0, 0, 0 } }; + for (int dy = 0; dy < 2; dy++) { + for (int dx = 0; dx < 2; dx++) { + int x0 = static_cast(std::floor(x)); + int y0 = static_cast(std::floor(y)); -namespace carto { + std::array color = readTileBitmapColor(bitmap, x0 + dx, y0 + dy); + for (int i = 0; i < 4; i++) { + result[i] += color[i] * (dx == 0 ? x0 + 1.0f - x : x - x0) * (dy == 0 ? y0 + 1.0f - y : y - y0); + } + } + } + return std::array { { static_cast(result[0]), static_cast(result[1]), static_cast(result[2]), static_cast(result[3]) } }; + } - HillshadeRasterTileLayer::HillshadeRasterTileLayer(const std::shared_ptr& dataSource) : - RasterTileLayer(dataSource), + double readPixelAltitude(const std::shared_ptr& tileBitmap, const carto::MapBounds& tileBounds, const carto::MapPos& pos, const std::array& components) { + int tileSize = tileBitmap->getWidth(); + float pixelX = (pos.getX() - tileBounds.getMin().getX()) / (tileBounds.getMax().getX() - tileBounds.getMin().getX()) * tileSize; + float pixelY = tileSize - (pos.getY() - tileBounds.getMin().getY()) / (tileBounds.getMax().getY() - tileBounds.getMin().getY()) * tileSize; + std::array interpolatedComponents = readTileBitmapColor(tileBitmap, std::round(pixelX), std::round(pixelY)); + double altitude = (components[0] * interpolatedComponents[0] + components[1] * interpolatedComponents[1] + components[2] * interpolatedComponents[2] + components[3] * interpolatedComponents[3]/255.0f); + return altitude; + } +} + +namespace carto +{ + + HillshadeRasterTileLayer::HillshadeRasterTileLayer(const std::shared_ptr &dataSource, const std::shared_ptr &elevationDecoder) : RasterTileLayer(dataSource), + _elevationDecoder(elevationDecoder), _contrast(0.5f), _heightScale(1.0f), _shadowColor(0, 0, 0, 255), - _highlightColor(255, 255, 255, 255) + _highlightColor(255, 255, 255, 255), + _illuminationDirection(67), + _illuminationMapRotationEnabled(true) { } - - HillshadeRasterTileLayer::~HillshadeRasterTileLayer() { + + HillshadeRasterTileLayer::~HillshadeRasterTileLayer() + { } - - float HillshadeRasterTileLayer::getContrast() const { + + float HillshadeRasterTileLayer::getContrast() const + { std::lock_guard lock(_mutex); return _contrast; } - void HillshadeRasterTileLayer::setContrast(float contrast) { + void HillshadeRasterTileLayer::setContrast(float contrast) + { { std::lock_guard lock(_mutex); _contrast = std::min(1.0f, std::max(0.0f, contrast)); @@ -42,12 +110,14 @@ namespace carto { tilesChanged(false); } - float HillshadeRasterTileLayer::getHeightScale() const { + float HillshadeRasterTileLayer::getHeightScale() const + { std::lock_guard lock(_mutex); return _heightScale; } - void HillshadeRasterTileLayer::setHeightScale(float heightScale) { + void HillshadeRasterTileLayer::setHeightScale(float heightScale) + { { std::lock_guard lock(_mutex); _heightScale = heightScale; @@ -55,12 +125,14 @@ namespace carto { tilesChanged(false); } - Color HillshadeRasterTileLayer::getShadowColor() const { + Color HillshadeRasterTileLayer::getShadowColor() const + { std::lock_guard lock(_mutex); return _shadowColor; } - void HillshadeRasterTileLayer::setShadowColor(const Color& color) { + void HillshadeRasterTileLayer::setShadowColor(const Color &color) + { { std::lock_guard lock(_mutex); _shadowColor = color; @@ -68,12 +140,14 @@ namespace carto { redraw(); } - Color HillshadeRasterTileLayer::getHighlightColor() const { + Color HillshadeRasterTileLayer::getHighlightColor() const + { std::lock_guard lock(_mutex); return _highlightColor; } - void HillshadeRasterTileLayer::setHighlightColor(const Color& color) { + void HillshadeRasterTileLayer::setHighlightColor(const Color &color) + { { std::lock_guard lock(_mutex); _highlightColor = color; @@ -81,22 +155,55 @@ namespace carto { redraw(); } - bool HillshadeRasterTileLayer::onDrawFrame(float deltaSeconds, BillboardSorter& billboardSorter, const ViewState& viewState) { + float HillshadeRasterTileLayer::getIlluminationDirection() const + { + std::lock_guard lock(_mutex); + return _illuminationDirection; + } + void HillshadeRasterTileLayer::setIlluminationDirection(float direction) + { + { + std::lock_guard lock(_mutex); + _illuminationDirection = direction; + } + redraw(); + } + bool HillshadeRasterTileLayer::getIlluminationMapRotationEnabled() const + { + std::lock_guard lock(_mutex); + return _illuminationMapRotationEnabled; + } + void HillshadeRasterTileLayer::setIlluminationMapRotationEnabled(bool enabled) + { + { + std::lock_guard lock(_mutex); + _illuminationMapRotationEnabled = enabled; + } + redraw(); + } + + bool HillshadeRasterTileLayer::onDrawFrame(float deltaSeconds, BillboardSorter &billboardSorter, const ViewState &viewState) + { updateTileLoadListener(); - if (auto mapRenderer = getMapRenderer()) { + if (auto mapRenderer = getMapRenderer()) + { float opacity = getOpacity(); - if (opacity < 1.0f) { + if (opacity < 1.0f) + { mapRenderer->clearAndBindScreenFBO(Color(0, 0, 0, 0), false, false); } _tileRenderer->setRasterFilterMode(getRasterFilterMode()); _tileRenderer->setNormalMapShadowColor(getShadowColor()); _tileRenderer->setNormalMapHighlightColor(getHighlightColor()); + _tileRenderer->setNormalIlluminationDirection(getIlluminationDirection()); + _tileRenderer->setNormalIlluminationMapRotationEnabled(getIlluminationMapRotationEnabled()); bool refresh = _tileRenderer->onDrawFrame(deltaSeconds, viewState); - if (opacity < 1.0f) { + if (opacity < 1.0f) + { mapRenderer->blendAndUnbindScreenFBO(opacity); } @@ -104,8 +211,9 @@ namespace carto { } return false; } - - std::shared_ptr HillshadeRasterTileLayer::createVectorTile(const MapTile& tile, const std::shared_ptr& bitmap) const { + + std::shared_ptr HillshadeRasterTileLayer::createVectorTile(const MapTile &tile, const std::shared_ptr &bitmap) const + { std::uint8_t alpha = 0; std::array scales; { @@ -113,21 +221,22 @@ namespace carto { alpha = static_cast(_contrast * 255.0f); float exaggeration = tile.getZoom() < 2 ? 0.2f : tile.getZoom() < 5 ? 0.3f : 0.35f; float scale = 16 * _heightScale * static_cast(bitmap->getHeight() * std::pow(2.0, tile.getZoom() * (1 - exaggeration)) / 40075016.6855785); - scales = std::array { 65536 * scale, 256 * scale, scale, 0.0f }; + scales = _elevationDecoder->getVectorTileScales(); + std::transform(scales.begin(), scales.end(), scales.begin(), [&scale](float &c) { return c * scale; }); } - + // Build normal map from height map vt::TileId vtTileId(tile.getZoom(), tile.getX(), tile.getY()); std::shared_ptr rgbaBitmap = bitmap->getRGBABitmap(); - auto rgbaBitmapDataPtr = reinterpret_cast(rgbaBitmap->getPixelData().data()); + auto rgbaBitmapDataPtr = reinterpret_cast(rgbaBitmap->getPixelData().data()); std::vector rgbaBitmapData(rgbaBitmapDataPtr, rgbaBitmapDataPtr + rgbaBitmap->getWidth() * rgbaBitmap->getHeight()); auto vtBitmap = std::make_shared(rgbaBitmap->getWidth(), rgbaBitmap->getHeight(), std::move(rgbaBitmapData)); vt::NormalMapBuilder normalMapBuilder(scales, alpha); std::shared_ptr normalMap = normalMapBuilder.buildNormalMapFromHeightMap(vtTileId, vtBitmap); - auto normalMapDataPtr = reinterpret_cast(normalMap->data.data()); + auto normalMapDataPtr = reinterpret_cast(normalMap->data.data()); std::vector normalMapData(normalMapDataPtr, normalMapDataPtr + normalMap->data.size() * sizeof(std::uint32_t)); auto tileBitmap = std::make_shared(vt::TileBitmap::Type::NORMALMAP, vt::TileBitmap::Format::RGBA, normalMap->width, normalMap->height, std::move(normalMapData)); - + // Build vector tile from created normal map float tileSize = 256.0f; // 'normalized' tile size in pixels. Not really important std::shared_ptr tileBackground = std::make_shared(vt::Color(), std::shared_ptr()); @@ -138,4 +247,107 @@ namespace carto { return std::make_shared(vtTileId, tileSize, tileBackground, std::vector > { tileLayer }); } -} + std::shared_ptr HillshadeRasterTileLayer::getTileDataBitmap(std::shared_ptr tileData) const { + std::shared_ptr binaryData = tileData->getData(); + if (!binaryData) { + Log::Error("HillshadeRasterTileLayer::getTileDataBitmap: Null tile binary data"); + return NULL; + } + int size = binaryData->size(); + std::shared_ptr tileBitmap = Bitmap::CreateFromCompressed(binaryData); + return tileBitmap; + } + + double HillshadeRasterTileLayer::getElevation(const MapPos &pos) const + { + std::shared_ptr dataSource = getDataSource(); + // we need to transform pos to dataSource projection + // TODO: how to check if pos is in Wgs84? + std::shared_ptr projection = dataSource->getProjection(); + MapPos dataSourcePos = projection->fromWgs84(pos); + + // The tile is flipped so to get the bitmap we need to flip it + MapTile mapTile = TileUtils::CalculateMapTile(dataSourcePos, dataSource->getMaxZoom(), projection); + MapTile flippedMapTile = mapTile.getFlipped(); + + std::shared_ptr tileData = _dataSource->loadTile(flippedMapTile); + while(tileData && tileData->isReplaceWithParent()) { + mapTile = mapTile.getParent(); + flippedMapTile = mapTile.getFlipped(); + tileData = _dataSource->loadTile(flippedMapTile); + } + if (!tileData) { + Log::Error("ElevationDecoder::getElevation: no tile found to get elevation"); + return -1000000; + } + std::shared_ptr tileBitmap = getTileDataBitmap(tileData); + if (!tileBitmap) { + Log::Error("ElevationDecoder::getElevation: Null tile bitmap"); + return -1000000; + } + std::array components = _elevationDecoder->getColorComponentCoefficients(); + return readPixelAltitude(tileBitmap, TileUtils::CalculateMapTileBounds(mapTile, projection), dataSourcePos, components); + } + std::vector HillshadeRasterTileLayer::getElevations(const std::vector poses) const + { + std::shared_ptr dataSource = getDataSource(); + std::map>> indexedTiles; + std::vector results; + std::shared_ptr projection = dataSource->getProjection(); + std::array components = _elevationDecoder->getColorComponentCoefficients(); + for (auto it = poses.begin(); it != poses.end(); it++) { + // TODO: how to check if pos is in Wgs84? + MapPos dataSourcePos = projection->fromWgs84(*it); + MapTile mapTile = TileUtils::CalculateMapTile(dataSourcePos, dataSource->getMaxZoom(), projection); + + long long tileId = mapTile.getTileId(); + std::map>>::iterator iter(indexedTiles.find(tileId)); + std::shared_ptr tileData; + if (iter == indexedTiles.end()) { + // no cached bitmap found lets get it from TileData + // The tile is flipped so to get the bitmap we need to flip it + MapTile flippedMapTile = mapTile.getFlipped(); + tileData = _dataSource->loadTile(flippedMapTile); + // get the parent tile if necessary + while(tileData && tileData->isReplaceWithParent()) { + mapTile = mapTile.getParent(); + tileId = mapTile.getTileId(); + iter = (indexedTiles.find(tileId)); + // if the parent tile is cached let's stop + if (iter != indexedTiles.end()) { + break; + } + flippedMapTile = mapTile.getFlipped(); + tileData = _dataSource->loadTile(flippedMapTile); + } + } + + if (iter != indexedTiles.end()) { + // we found a cached bitmap + std::pair> pair = iter->second; + const std::shared_ptr& tileBitmap = pair.second; + const MapBounds& tileBounds = pair.first; + double altitude = readPixelAltitude(tileBitmap, tileBounds, dataSourcePos, components); + results.push_back(altitude); + continue; + } + if (tileData) { + // read from the tile data + // then put the bitmap in the cache for next points + long long tileId = mapTile.getTileId(); + std::shared_ptr tileBitmap = getTileDataBitmap(tileData); + MapBounds tileBounds = TileUtils::CalculateMapTileBounds(mapTile, projection); + std::pair> pair = std::make_pair(tileBounds, tileBitmap); + indexedTiles.insert(std::pair>>(tileId, pair)); + double altitude = readPixelAltitude(tileBitmap, tileBounds, dataSourcePos, components); + results.push_back(altitude); + } else { + // in case we did not find an elevation still return something + // so that the user can now for which point each elevation was + results.push_back(-1000000); + } + + } + return results; + } +} // namespace carto diff --git a/all/native/layers/HillshadeRasterTileLayer.h b/all/native/layers/HillshadeRasterTileLayer.h index e11fcca42..29d2ba6b8 100644 --- a/all/native/layers/HillshadeRasterTileLayer.h +++ b/all/native/layers/HillshadeRasterTileLayer.h @@ -8,7 +8,9 @@ #define _CARTO_HILLSHADERASTERTILELAYER_H_ #include "graphics/Color.h" +#include "components/DirectorPtr.h" #include "layers/RasterTileLayer.h" +#include "rastertiles/ElevationDecoder.h" namespace carto { @@ -23,7 +25,7 @@ namespace carto { * Constructs a HillshadeRasterTileLayer object from a data source. * @param dataSource The data source from which this layer loads data. */ - explicit HillshadeRasterTileLayer(const std::shared_ptr& dataSource); + explicit HillshadeRasterTileLayer(const std::shared_ptr& dataSource, const std::shared_ptr& elevationDecoder); virtual ~HillshadeRasterTileLayer(); /** @@ -69,16 +71,46 @@ namespace carto { * @param color The new highlight color of the layer. */ void setHighlightColor(const Color& color); + /** + * Returns the illumination direction of the layer. + * @return direction in degrees. + */ + float getIlluminationDirection() const; + /** + * Sets the illumination direction. + * @param direction in degrees. + */ + void setIlluminationDirection(float direction); + /** + * Returns wheter the illumination direction should change with the map rotation. + * @return enabled + */ + bool getIlluminationMapRotationEnabled() const; + /** + * Sets wheter the illumination direction should change with the map rotation. + * @param enabled whether to enable or not. + */ + void setIlluminationMapRotationEnabled(bool enabled); + + double getElevation(const MapPos& pos) const; + std::vector getElevations(const std::vector poses) const; protected: virtual bool onDrawFrame(float deltaSeconds, BillboardSorter& billboardSorter, const ViewState& viewState); virtual std::shared_ptr createVectorTile(const MapTile& tile, const std::shared_ptr& bitmap) const; + std::shared_ptr getTileDataBitmap(std::shared_ptr tileData) const; + std::shared_ptr getMapTileBitmap(const MapTile& mapTile) const; + + const DirectorPtr _elevationDecoder; + float _contrast; float _heightScale; Color _shadowColor; Color _highlightColor; + float _illuminationDirection; + bool _illuminationMapRotationEnabled; }; } diff --git a/all/native/rastertiles/ElevationDecoder.cpp b/all/native/rastertiles/ElevationDecoder.cpp new file mode 100644 index 000000000..43784a798 --- /dev/null +++ b/all/native/rastertiles/ElevationDecoder.cpp @@ -0,0 +1,16 @@ +#include "ElevationDecoder.h" +#include "utils/Log.h" +#include "utils/TileUtils.h" + +#include + +namespace carto +{ + ElevationDecoder::~ElevationDecoder() + { + } + + ElevationDecoder::ElevationDecoder() + { + } +} // namespace carto diff --git a/all/native/rastertiles/ElevationDecoder.h b/all/native/rastertiles/ElevationDecoder.h new file mode 100644 index 000000000..891d37ef6 --- /dev/null +++ b/all/native/rastertiles/ElevationDecoder.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 CartoDB. All rights reserved. + * Copying and using this code is allowed only according + * to license terms, as given in https://cartodb.com/terms/ + */ + +#ifndef _CARTO_ELEVATIONDECODER_H_ +#define _CARTO_ELEVATIONDECODER_H_ + +#include "graphics/Color.h" + +#include +#include +#include +#include +#include + +#include + +#include + +namespace carto { + /** + * Abstract base class for raster elevation decoders. + */ + class ElevationDecoder { + public: + /** + * Constructs an ElevationDecoder. + */ + ElevationDecoder(); + virtual ~ElevationDecoder(); + + virtual std::array getVectorTileScales() const = 0; + virtual std::array getColorComponentCoefficients() const = 0; + + }; + +} + +#endif diff --git a/all/native/rastertiles/MapBoxElevationDataDecoder.cpp b/all/native/rastertiles/MapBoxElevationDataDecoder.cpp new file mode 100644 index 000000000..69a8097b9 --- /dev/null +++ b/all/native/rastertiles/MapBoxElevationDataDecoder.cpp @@ -0,0 +1,27 @@ +#include "MapBoxElevationDataDecoder.h" + +namespace carto +{ + + MapBoxElevationDataDecoder::MapBoxElevationDataDecoder() : + ElevationDecoder() + { + } + + MapBoxElevationDataDecoder::~MapBoxElevationDataDecoder() + { + } + + std::array MapBoxElevationDataDecoder::getColorComponentCoefficients() const + { + return COMPONENTS; + } + + std::array MapBoxElevationDataDecoder::getVectorTileScales() const + { + return SCALES; + } + + const std::array MapBoxElevationDataDecoder::COMPONENTS = std::array{256 * 256 * 0.1f, 256 * 0.1f, 0.1f, -10000.0f}; + const std::array MapBoxElevationDataDecoder::SCALES = std::array{256 * 256, 256.0f, 1.0f, 0.0f}; +} // namespace carto diff --git a/all/native/rastertiles/MapBoxElevationDataDecoder.h b/all/native/rastertiles/MapBoxElevationDataDecoder.h new file mode 100644 index 000000000..234570638 --- /dev/null +++ b/all/native/rastertiles/MapBoxElevationDataDecoder.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 CartoDB. All rights reserved. + * Copying and using this code is allowed only according + * to license terms, as given in https://cartodb.com/terms/ + */ + +#ifndef _CARTO_MAPBOXELEVATIONDATADECODER_H_ +#define _CARTO_MAPBOXELEVATIONDATADECODER_H_ + +#include "rastertiles/ElevationDecoder.h" + +#include +#include +#include +#include + +namespace carto { + + /** + * A decoder for MapBox encoded elevation tiles + */ + class MapBoxElevationDataDecoder : public ElevationDecoder { + public: + /** + * Constructs a new MapBoxElevationDataDecoder. + */ + MapBoxElevationDataDecoder(); + virtual ~MapBoxElevationDataDecoder(); + + virtual std::array getVectorTileScales() const; + virtual std::array getColorComponentCoefficients() const; + + private : + static const std::array COMPONENTS; + static const std::array SCALES; + }; + +} + +#endif diff --git a/all/native/rastertiles/TerrariumElevationDataDecoder.cpp b/all/native/rastertiles/TerrariumElevationDataDecoder.cpp new file mode 100644 index 000000000..ec9c9a381 --- /dev/null +++ b/all/native/rastertiles/TerrariumElevationDataDecoder.cpp @@ -0,0 +1,27 @@ +#include "TerrariumElevationDataDecoder.h" + +namespace carto +{ + + TerrariumElevationDataDecoder::TerrariumElevationDataDecoder() : + ElevationDecoder() + { + } + + TerrariumElevationDataDecoder::~TerrariumElevationDataDecoder() + { + } + + std::array TerrariumElevationDataDecoder::getColorComponentCoefficients() const + { + return COMPONENTS; + } + + std::array TerrariumElevationDataDecoder::getVectorTileScales() const + { + return SCALES; + } + + const std::array TerrariumElevationDataDecoder::COMPONENTS = std::array{256.0f, 1.0f, 1.0f / 256, -32768.0f}; + const std::array TerrariumElevationDataDecoder::SCALES = std::array{256.0f, 1.0f, 1.0f / 256, -32768.0f}; +} // namespace carto diff --git a/all/native/rastertiles/TerrariumElevationDataDecoder.h b/all/native/rastertiles/TerrariumElevationDataDecoder.h new file mode 100644 index 000000000..b1d9c234a --- /dev/null +++ b/all/native/rastertiles/TerrariumElevationDataDecoder.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 CartoDB. All rights reserved. + * Copying and using this code is allowed only according + * to license terms, as given in https://cartodb.com/terms/ + */ + +#ifndef _CARTO_TERRARIUMELEVATIONDATADECODER_H_ +#define _CARTO_TERRARIUMELEVATIONDATADECODER_H_ + +#include "rastertiles/ElevationDecoder.h" + +#include +#include +#include +#include + +namespace carto { + + /** + * A decoder for Terrarium encoded elevation tiles + */ + class TerrariumElevationDataDecoder : public ElevationDecoder { + public: + /** + * Constructs a new TerrariumElevationDataDecoder. + */ + TerrariumElevationDataDecoder(); + virtual ~TerrariumElevationDataDecoder(); + + virtual std::array getVectorTileScales() const; + virtual std::array getColorComponentCoefficients() const; + + private : + static const std::array COMPONENTS; + static const std::array SCALES; + }; + +} + +#endif diff --git a/all/native/renderers/TileRenderer.cpp b/all/native/renderers/TileRenderer.cpp index d95e61d22..6ee1f6071 100644 --- a/all/native/renderers/TileRenderer.cpp +++ b/all/native/renderers/TileRenderer.cpp @@ -9,6 +9,7 @@ #include "renderers/utils/GLResourceManager.h" #include "renderers/utils/VTRenderer.h" #include "utils/Log.h" +#include "utils/Const.h" #include #include @@ -34,6 +35,9 @@ namespace carto { _horizontalLayerOffset(0), _viewDir(0, 0, 0), _mainLightDir(0, 0, 0), + _normalIlluminationMapRotationEnabled(false), + _normalIlluminationDirection(45), + _mapRotation(0), _tiles(), _mutex() { @@ -96,6 +100,15 @@ namespace carto { std::lock_guard lock(_mutex); _normalMapHighlightColor = color; } + void TileRenderer::setNormalIlluminationDirection(float direction) { + std::lock_guard lock(_mutex); + _normalIlluminationDirection = direction; + } + + void TileRenderer::setNormalIlluminationMapRotationEnabled(bool enabled) { + std::lock_guard lock(_mutex); + _normalIlluminationMapRotationEnabled = enabled; + } void TileRenderer::offsetLayerHorizontally(double offset) { std::lock_guard lock(_mutex); @@ -119,6 +132,8 @@ namespace carto { tileRenderer->setSubTileBlending(_subTileBlending); tileRenderer->setRasterFilterMode(_rasterFilterMode); + + _mapRotation = viewState.getRotation(); _viewDir = cglib::unit(viewState.getFocusPosNormal()); if (auto options = _options.lock()) { MapPos internalFocusPos = viewState.getProjectionSurface()->calculateMapPos(viewState.getFocusPos()); @@ -324,11 +339,16 @@ namespace carto { tileRenderer->setLightingShader3D(lightingShader3D); vt::GLTileRenderer::LightingShader lightingShaderNormalMap(false, LIGHTING_SHADER_NORMALMAP, [this](GLuint shaderProgram, const vt::ViewState& viewState) { + float azimuthal = _normalIlluminationDirection * Const::DEG_TO_RAD; + if (_normalIlluminationMapRotationEnabled) { + azimuthal -= _mapRotation * Const::DEG_TO_RAD; + } + MapVec viewDir = MapVec(std::cos(azimuthal), std::sin(azimuthal)); float shadowAlpha = _normalMapShadowColor.getA() / 255.0f; glUniform4f(glGetUniformLocation(shaderProgram, "u_shadowColor"), _normalMapShadowColor.getR() * shadowAlpha / 255.0f, _normalMapShadowColor.getG() * shadowAlpha / 255.0f, _normalMapShadowColor.getB() * shadowAlpha / 255.0f, shadowAlpha); float highlightAlpha = _normalMapHighlightColor.getA() / 255.0f; glUniform4f(glGetUniformLocation(shaderProgram, "u_highlightColor"), _normalMapHighlightColor.getR() * highlightAlpha / 255.0f, _normalMapHighlightColor.getG() * highlightAlpha / 255.0f, _normalMapHighlightColor.getB() * highlightAlpha / 255.0f, highlightAlpha); - glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, _mainLightDir.data()); + glUniform3fv(glGetUniformLocation(shaderProgram, "u_lightDir"), 1, cViewDir.data()); }); tileRenderer->setLightingShaderNormalMap(lightingShaderNormalMap); } diff --git a/all/native/renderers/TileRenderer.h b/all/native/renderers/TileRenderer.h index 4b594b94a..2d6d3f93c 100644 --- a/all/native/renderers/TileRenderer.h +++ b/all/native/renderers/TileRenderer.h @@ -53,6 +53,8 @@ namespace carto { void setRasterFilterMode(vt::RasterFilterMode filterMode); void setNormalMapShadowColor(const Color& color); void setNormalMapHighlightColor(const Color& color); + void setNormalIlluminationMapRotationEnabled(bool enabled); + void setNormalIlluminationDirection(float direction); void offsetLayerHorizontally(double offset); @@ -89,6 +91,10 @@ namespace carto { double _horizontalLayerOffset; cglib::vec3 _viewDir; cglib::vec3 _mainLightDir; + double _normalIlluminationDirection; + bool _normalIlluminationMapRotationEnabled; + double _mapRotation; + std::map > _tiles; mutable std::mutex _mutex; diff --git a/all/native/routing/ValhallaOfflineRoutingService.cpp b/all/native/routing/ValhallaOfflineRoutingService.cpp index 18982877d..82d845f68 100644 --- a/all/native/routing/ValhallaOfflineRoutingService.cpp +++ b/all/native/routing/ValhallaOfflineRoutingService.cpp @@ -84,7 +84,6 @@ namespace carto { std::lock_guard lock(_mutex); return ValhallaRoutingProxy::CalculateRoute(std::vector > { _database }, _profile, _configuration, request); } - } #endif diff --git a/all/native/routing/ValhallaRoutingProxy.h b/all/native/routing/ValhallaRoutingProxy.h index b1bd22fd9..209ea5e18 100644 --- a/all/native/routing/ValhallaRoutingProxy.h +++ b/all/native/routing/ValhallaRoutingProxy.h @@ -27,6 +27,8 @@ namespace carto { class RoutingResult; class RouteMatchingRequest; class RouteMatchingResult; + class TileDataSource; + class ElevationDecoder; class ValhallaRoutingProxy { public: diff --git a/android/csharp/UI/MapView.cs b/android/csharp/UI/MapView.cs index 383eecba8..0a0592e10 100644 --- a/android/csharp/UI/MapView.cs +++ b/android/csharp/UI/MapView.cs @@ -197,6 +197,8 @@ public override bool OnTouchEvent(MotionEvent motionEvent) { _baseMapView.OnInputEvent(NativeActionCancel, NativeNoCoordinate, NativeNoCoordinate, NativeNoCoordinate, NativeNoCoordinate); + _pointer1Id = InvalidPointerId; + _pointer2Id = InvalidPointerId; break; case MotionEventActions.Up: case MotionEventActions.PointerUp: diff --git a/android/java/com/carto/ui/MapView.java b/android/java/com/carto/ui/MapView.java index 20225737a..c7233fdf2 100644 --- a/android/java/com/carto/ui/MapView.java +++ b/android/java/com/carto/ui/MapView.java @@ -252,6 +252,8 @@ public synchronized boolean onTouchEvent(MotionEvent event) { baseMapView.onInputEvent(NATIVE_ACTION_CANCEL, NATIVE_NO_COORDINATE, NATIVE_NO_COORDINATE, NATIVE_NO_COORDINATE, NATIVE_NO_COORDINATE); + pointer1Index = INVALID_POINTER_ID; + pointer2Index = INVALID_POINTER_ID; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: diff --git a/scripts/build-ios.py b/scripts/build-ios.py index 8ad0faeab..d474a8ba9 100644 --- a/scripts/build-ios.py +++ b/scripts/build-ios.py @@ -2,40 +2,48 @@ import sys import re import shutil +import itertools import argparse import string from build.sdk_build_utils import * IOS_ARCHS = ['i386', 'x86_64', 'armv7', 'arm64'] -def updateUmbrellaHeader(filename, args): +def updateUmbrellaHeader(filename, defines): with open(filename, 'r') as f: lines = f.readlines() for i in range(0, len(lines)): match = re.search('^\s*#import\s+"(.*)".*', lines[i].rstrip('\n')) if match: - lines[i] = '#import \n' % match.group(1) + headerFilename = match.group(1).split('/')[-1] + if not headerFilename.startswith('NT'): + headerFilename = 'NT%s' % headerFilename + lines[i] = '#import \n' % headerFilename for i in range(0, len(lines)): if re.search('^\s*#define\s+.*$', lines[i].rstrip('\n')): break - lines = lines[:i+1] + ['\n'] + ['#define %s\n' % define for define in args.defines.split(';') if define] + lines[i+1:] + lines = lines[:i+1] + ['\n'] + ['#define %s\n' % define for define in defines.split(';') if define] + lines[i+1:] with open(filename, 'w') as f: f.writelines(lines) -def updatePrivateHeader(filename, args): +def updatePublicHeader(filename): with open(filename, 'r') as f: lines = f.readlines() + externCMode = False for i in range(0, len(lines)): - match = re.search('^\s*#include\s+"(.*)".*', lines[i].rstrip('\n')) - if match: - lines[i] = '#include \n' % match.group(1) + if lines[i].find('extern "C"') != -1: + externCMode = True match = re.search('^\s*#import\s+"(.*)".*', lines[i].rstrip('\n')) if match: - lines[i] = '#import \n' % match.group(1) + headerFilename = match.group(1) + if externCMode: + lines[i] = '#ifdef __cplusplus\n}\n#endif\n#import "%s"\n#ifdef __cplusplus\nextern "C" {\n#endif\n' % headerFilename + else: + lines[i] = '#import "%s"\n' % headerFilename with open(filename, 'w') as f: f.writelines(lines) -def buildModuleMap(filename, publicHeaders, privateHeaders): +def buildModuleMap(filename, publicHeaders): with open(filename, 'w') as f: f.write('framework module CartoMobileSDK {\n') f.write(' umbrella header "CartoMobileSDK.h"\n') @@ -43,18 +51,50 @@ def buildModuleMap(filename, publicHeaders, privateHeaders): f.write(' header "%s"\n' % header) f.write(' export *\n') f.write(' module * { export * }\n') - f.write(' explicit module Private {\n') - f.write(' requires cplusplus\n') - for header in privateHeaders: - f.write(' header "%s"\n' % header) - f.write(' }\n') f.write('}\n') -def buildIOSLib(args, arch): +def copyHeaders(args, baseDir, outputDir): + proxyHeaderDir = '%s/generated/ios-objc/proxies' % baseDir + destDir = '%s/Headers' % outputDir + publicHeaders = [] + makedirs(destDir) + + currentDir = os.getcwd() + os.chdir(proxyHeaderDir) + for dirpath, dirnames, filenames in os.walk('.'): + for filename in filenames: + if filename.endswith('.h'): + publicHeaders.append(filename) + if not copyfile(os.path.join(dirpath, filename), '%s/%s' % (destDir, filename)): + os.chdir(currentDir) + return False + updatePublicHeader('%s/%s' % (destDir, filename)) + os.chdir(currentDir) + + extraHeaders = ['%s/ios/objc/utils/ExceptionWrapper.h', '%s/ios/objc/ui/MapView.h'] + if args.metalangle: + for extraHeader in ['MGLKit.h', 'MGLKitPlatform.h', 'MGLContext.h', 'MGLKView.h', 'MGLLayer.h', 'MGLKViewController.h']: + extraHeaders += ['%s/libs-external/angle-metal/include/' + extraHeader] + for extraHeader in extraHeaders: + dirpath, filename = (extraHeader % baseDir).rsplit('/', 1) + destFilename = filename if filename.startswith('MGL') else 'NT%s' % filename + publicHeaders.append(destFilename) + if not copyfile(os.path.join(dirpath, filename), '%s/%s' % (destDir, destFilename)): + return False + + if not copyfile('%s/ios/objc/CartoMobileSDK.h' % baseDir, '%s/CartoMobileSDK.h' % destDir): + return False + updateUmbrellaHeader('%s/CartoMobileSDK.h' % destDir, args.defines) + + makedirs('%s/Modules' % outputDir) + buildModuleMap('%s/Modules/module.modulemap' % outputDir, publicHeaders) + return True + +def buildIOSLib(args, arch, outputDir=None): platform = 'OS' if arch.startswith('arm') else 'SIMULATOR' version = getVersion(args.buildnumber) if args.configuration == 'Release' else 'Devel' baseDir = getBaseDir() - buildDir = getBuildDir('ios', '%s-%s' % (platform, arch)) + buildDir = outputDir or getBuildDir('ios', '%s-%s' % (platform, arch)) defines = ["-D%s" % define for define in args.defines.split(';') if define] options = ["-D%s" % option for option in args.cmakeoptions.split(';') if option] @@ -82,17 +122,16 @@ def buildIOSLib(args, arch): '--config', args.configuration ]) -def buildIOSFramework(args, archs): - shutil.rmtree(getDistDir('ios'), True) - +def buildIOSFramework(args, archs, outputDir=None): platformArchs = [('OS' if arch.startswith('arm') else 'SIMULATOR', arch) for arch in archs] baseDir = getBaseDir() - distDir = getDistDir('ios') + distDir = outputDir or getDistDir('ios') if args.sharedlib: - outputDir = '%s/CartoMobileSDK.framework' % distDir + frameworkDir = '%s/CartoMobileSDK.framework' % distDir else: - outputDir = '%s/CartoMobileSDK.framework/Versions/A' % distDir - makedirs(outputDir) + frameworkDir = '%s/CartoMobileSDK.framework/Versions/A' % distDir + shutil.rmtree(distDir, True) + makedirs(frameworkDir) libFilePaths = [] for platform, arch in platformArchs: @@ -108,21 +147,21 @@ def buildIOSFramework(args, archs): libFilePaths.append(libFilePath) if not execute('lipo', baseDir, - '-output', '%s/CartoMobileSDK' % outputDir, + '-output', '%s/CartoMobileSDK' % frameworkDir, '-create', *libFilePaths ): return False if args.sharedlib: - if not execute('install_name_tool', outputDir, + if not execute('install_name_tool', frameworkDir, '-id', '@rpath/CartoMobileSDK.framework/CartoMobileSDK', 'CartoMobileSDK' ): return False - if not copyfile('%s/scripts/ios/Info.plist' % baseDir, '%s/Info.plist' % outputDir): + if not copyfile('%s/scripts/ios/Info.plist' % baseDir, '%s/Info.plist' % frameworkDir): return False - makedirs('%s/Headers' % outputDir) + makedirs('%s/Headers' % frameworkDir) if not args.sharedlib: if not makesymlink('%s/CartoMobileSDK.framework/Versions' % distDir, 'A', 'Current'): return False @@ -130,43 +169,40 @@ def buildIOSFramework(args, archs): return False if not makesymlink('%s/CartoMobileSDK.framework' % distDir, 'Versions/A/Headers', 'Headers'): return False - if not makesymlink('%s/CartoMobileSDK.framework' % distDir, 'Versions/A/PrivateHeaders', 'PrivateHeaders'): - return False if not makesymlink('%s/CartoMobileSDK.framework' % distDir, 'Versions/A/CartoMobileSDK', 'CartoMobileSDK'): return False + if not copyHeaders(args, baseDir, frameworkDir): + return False - publicHeaders = [] - privateHeaders = [] - headerDirTemplates = ['%s/all/native', '%s/ios/native', '%s/ios/objc', '%s/generated/ios-objc/proxies', '%s/libs-external/cglib'] - if args.metalangle: - headerDirTemplates.append('%s/libs-external/angle-metal/include') - for headerDirTemplate in headerDirTemplates: - headerDir = headerDirTemplate % baseDir - if not os.path.exists(headerDir): - continue - currentDir = os.getcwd() - os.chdir(headerDir) - for dirpath, dirnames, filenames in os.walk('.'): - for filename in filenames: - if filename.endswith('.h'): - destDir = '%s/Headers/%s' % (outputDir, dirpath) - if headerDirTemplate.find('objc') == -1: - destDir = '%s/PrivateHeaders/%s' % (outputDir, dirpath) - privateHeaders.append(os.path.normpath(os.path.join(dirpath, filename))) - elif filename != 'CartoMobileSDK.h': - publicHeaders.append(os.path.normpath(os.path.join(dirpath, filename))) - if not (makedirs(destDir) and copyfile(os.path.join(dirpath, filename), '%s/%s' % (destDir, filename))): - os.chdir(currentDir) - return False - if filename == 'CartoMobileSDK.h': - updateUmbrellaHeader('%s/%s' % (destDir, filename), args) - else: - updatePrivateHeader('%s/%s' % (destDir, filename), args) - os.chdir(currentDir) - makedirs('%s/Modules' % outputDir) - buildModuleMap('%s/Modules/module.modulemap' % outputDir, publicHeaders, privateHeaders) + if outputDir is None: + print("Output available in:\n%s" % distDir) + return True + +def buildIOSXCFramework(args, archs, outputDir=None): + platformArchs = [('OS' if arch.startswith('arm') else 'SIMULATOR', arch) for arch in archs] + groupedPlatformArchs = {} + for platform, arch in platformArchs: + groupedPlatformArchs[platform] = groupedPlatformArchs.get(platform, []) + [arch] + baseDir = getBaseDir() + distDir = outputDir or getDistDir('ios') + shutil.rmtree(distDir, True) + makedirs(distDir) - print("Output available in:\n%s" % distDir) + frameworkBuildDirs = [] + for platform, archs in groupedPlatformArchs.items(): + frameworkBuildDir = getBuildDir('ios-framework', '%s-%s' % (platform, '-'.join(archs))) + if not buildIOSFramework(args, archs, frameworkBuildDir): + return False + frameworkBuildDirs.append(frameworkBuildDir) + + if not execute('xcodebuild', baseDir, + '-create-xcframework', '-output', '%s/CartoMobileSDK.xcframework' % distDir, + *list(itertools.chain(*[['-framework', '%s/CartoMobileSDK.framework' % frameworkBuildDir] for frameworkBuildDir in frameworkBuildDirs])) + ): + return False + + if outputDir is None: + print("Output available in:\n%s" % distDir) return True def buildIOSCocoapod(args, buildpackage): @@ -201,6 +237,7 @@ def buildIOSCocoapod(args, buildpackage): parser.add_argument('--configuration', dest='configuration', default='Release', choices=['Release', 'RelWithDebInfo', 'Debug'], help='Configuration') parser.add_argument('--build-number', dest='buildnumber', default='', help='Build sequence number, goes to version str') parser.add_argument('--build-version', dest='buildversion', default='%s-devel' % SDK_VERSION, help='Build version, goes to distributions') +parser.add_argument('--build-xcframework', dest='buildxcframework', default=False, action='store_true', help='Build XCFramework') parser.add_argument('--build-cocoapod', dest='buildcocoapod', default=False, action='store_true', help='Build CocoaPod') parser.add_argument('--build-cocoapod-package', dest='buildcocoapodpackage', default=False, action='store_true', help='Build CocoaPod') parser.add_argument('--metalangle', dest='metalangle', default=False, action='store_true', help='Use MetalANGLE instead of Apple GL') @@ -223,8 +260,12 @@ def buildIOSCocoapod(args, buildpackage): if not buildIOSLib(args, arch): sys.exit(-1) -if not buildIOSFramework(args, args.iosarch): - sys.exit(-1) +if args.buildxcframework: + if not buildIOSXCFramework(args, args.iosarch): + sys.exit(-1) +else: + if not buildIOSFramework(args, args.iosarch): + sys.exit(-1) if args.buildcocoapod or args.buildcocoapodpackage: if not buildIOSCocoapod(args, args.buildcocoapodpackage):