Reduce memory use of FeatureIndex (#2364)
This commit is contained in:
@@ -24,7 +24,7 @@ void FileSourceRequest::onCancel(std::function<void()>&& callback) {
|
||||
void FileSourceRequest::setResponse(const Response& response) {
|
||||
// Copy, because calling the callback will sometimes self
|
||||
// destroy this object. We cannot move because this method
|
||||
// can be called more than one.
|
||||
// can be called more than once.
|
||||
auto callback = responseCallback;
|
||||
callback(response);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,90 @@ mbgl::Point<double> project(const mbgl::LatLng& coordinate, const mbgl::Transfor
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
constexpr auto expectedUniqueLayerIDs = 10;
|
||||
constexpr auto expectedUniqueLeaderIDs = 30;
|
||||
|
||||
RefIndexedSubfeature::RefIndexedSubfeature(std::size_t index_,
|
||||
const std::string& sourceLayerName_,
|
||||
const std::string& bucketName_,
|
||||
size_t sortIndex_,
|
||||
uint32_t bucketInstanceId_,
|
||||
uint16_t collisionGroupId_)
|
||||
: index(index_),
|
||||
sortIndex(sortIndex_),
|
||||
sourceLayerName(sourceLayerName_),
|
||||
bucketLeaderID(bucketName_),
|
||||
bucketInstanceId(bucketInstanceId_),
|
||||
collisionGroupId(collisionGroupId_) {}
|
||||
|
||||
IndexedSubfeature::IndexedSubfeature(const RefIndexedSubfeature& other)
|
||||
: IndexedSubfeature(other, other.getBucketInstanceId(), other.getCollisionGroupId()) {}
|
||||
|
||||
IndexedSubfeature::IndexedSubfeature(const RefIndexedSubfeature& other,
|
||||
uint32_t bucketInstanceId_,
|
||||
uint16_t collisionGroupId_)
|
||||
: IndexedSubfeature(other.getIndex(),
|
||||
other.getSourceLayerName(),
|
||||
other.getBucketLeaderID(),
|
||||
other.getSortIndex(),
|
||||
bucketInstanceId_,
|
||||
collisionGroupId_) {}
|
||||
|
||||
IndexedSubfeature::IndexedSubfeature(const IndexedSubfeature& other)
|
||||
: IndexedSubfeature(other.getIndex(),
|
||||
other.sourceLayerName,
|
||||
other.bucketLeaderID,
|
||||
other.getSortIndex(),
|
||||
other.getBucketInstanceId(),
|
||||
other.getCollisionGroupId()) {}
|
||||
|
||||
IndexedSubfeature::IndexedSubfeature(IndexedSubfeature&& other)
|
||||
: IndexedSubfeature(other.getIndex(),
|
||||
std::move(other.sourceLayerName),
|
||||
std::move(other.bucketLeaderID),
|
||||
other.getSortIndex(),
|
||||
other.getBucketInstanceId(),
|
||||
other.getCollisionGroupId()) {}
|
||||
|
||||
IndexedSubfeature::IndexedSubfeature(std::size_t index_,
|
||||
std::string sourceLayerName_,
|
||||
std::string bucketName_,
|
||||
size_t sortIndex_,
|
||||
uint32_t bucketInstanceId_,
|
||||
uint16_t collisionGroupId_)
|
||||
: RefIndexedSubfeature(index_,
|
||||
this->sourceLayerNameCopy,
|
||||
this->bucketLeaderIDCopy,
|
||||
sortIndex_,
|
||||
bucketInstanceId_,
|
||||
collisionGroupId_),
|
||||
sourceLayerNameCopy(std::move(sourceLayerName_)),
|
||||
bucketLeaderIDCopy(std::move(bucketName_)) {}
|
||||
|
||||
IndexedSubfeature& IndexedSubfeature::operator=(const IndexedSubfeature& other) {
|
||||
index = other.index;
|
||||
sourceLayerName = sourceLayerNameCopy;
|
||||
bucketLeaderID = bucketLeaderIDCopy;
|
||||
sortIndex = other.sortIndex;
|
||||
bucketInstanceId = other.bucketInstanceId;
|
||||
collisionGroupId = other.collisionGroupId;
|
||||
sourceLayerNameCopy = other.sourceLayerNameCopy;
|
||||
bucketLeaderIDCopy = other.bucketLeaderIDCopy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IndexedSubfeature& IndexedSubfeature::operator=(IndexedSubfeature&& other) {
|
||||
index = other.index;
|
||||
sourceLayerName = sourceLayerNameCopy;
|
||||
bucketLeaderID = bucketLeaderIDCopy;
|
||||
sortIndex = other.sortIndex;
|
||||
bucketInstanceId = other.bucketInstanceId;
|
||||
collisionGroupId = other.collisionGroupId;
|
||||
sourceLayerNameCopy = std::move(other.sourceLayerNameCopy);
|
||||
bucketLeaderIDCopy = std::move(other.bucketLeaderIDCopy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FeatureIndex::FeatureIndex(std::unique_ptr<const GeometryTileData> tileData_)
|
||||
: grid(util::EXTENT, util::EXTENT, util::EXTENT / 16), // 16x16 grid -> 32px cell
|
||||
tileData(std::move(tileData_)) {}
|
||||
@@ -41,12 +125,22 @@ void FeatureIndex::insert(const GeometryCollection& geometries,
|
||||
std::size_t index,
|
||||
const std::string& sourceLayerName,
|
||||
const std::string& bucketLeaderID) {
|
||||
if (uniqueLayerIDs.empty()) {
|
||||
uniqueLayerIDs.reserve(expectedUniqueLayerIDs);
|
||||
}
|
||||
const std::string& emplacedLayerName = *uniqueLayerIDs.insert(sourceLayerName).first;
|
||||
if (bucketLayerIDs.empty()) {
|
||||
bucketLayerIDs.reserve(expectedUniqueLeaderIDs);
|
||||
}
|
||||
const std::string& emplacedLeaderID =
|
||||
bucketLayerIDs.insert(std::make_pair(bucketLeaderID, std::vector<std::string>{})).first->first;
|
||||
|
||||
auto featureSortIndex = sortIndex++;
|
||||
for (const auto& ring : geometries) {
|
||||
auto envelope = mapbox::geometry::envelope(ring);
|
||||
const auto envelope = mapbox::geometry::envelope(ring);
|
||||
if (envelope.min.x < util::EXTENT && envelope.min.y < util::EXTENT && envelope.max.x >= 0 &&
|
||||
envelope.max.y >= 0) {
|
||||
grid.insert(IndexedSubfeature(index, sourceLayerName, bucketLeaderID, featureSortIndex),
|
||||
grid.insert(RefIndexedSubfeature(index, emplacedLayerName, emplacedLeaderID, featureSortIndex),
|
||||
{convertPoint<float>(envelope.min), convertPoint<float>(envelope.max)});
|
||||
}
|
||||
}
|
||||
@@ -74,17 +168,17 @@ void FeatureIndex::query(std::unordered_map<std::string, std::vector<Feature>>&
|
||||
|
||||
// Query the grid index
|
||||
mapbox::geometry::box<int16_t> box = mapbox::geometry::envelope(queryGeometry);
|
||||
std::vector<IndexedSubfeature> features = grid.query(
|
||||
std::vector<RefIndexedSubfeature> features = grid.query(
|
||||
{convertPoint<float>(box.min - additionalPadding), convertPoint<float>(box.max + additionalPadding)});
|
||||
|
||||
std::sort(features.begin(), features.end(), [](const IndexedSubfeature& a, const IndexedSubfeature& b) {
|
||||
return a.sortIndex > b.sortIndex;
|
||||
std::sort(features.begin(), features.end(), [](const RefIndexedSubfeature& a, const RefIndexedSubfeature& b) {
|
||||
return a.getSortIndex() > b.getSortIndex();
|
||||
});
|
||||
size_t previousSortIndex = std::numeric_limits<size_t>::max();
|
||||
for (const auto& indexedFeature : features) {
|
||||
// If this feature is the same as the previous feature, skip it.
|
||||
if (indexedFeature.sortIndex == previousSortIndex) continue;
|
||||
previousSortIndex = indexedFeature.sortIndex;
|
||||
if (indexedFeature.getSortIndex() == previousSortIndex) continue;
|
||||
previousSortIndex = indexedFeature.getSortIndex();
|
||||
|
||||
addFeature(result,
|
||||
indexedFeature,
|
||||
@@ -109,11 +203,12 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
|
||||
if (!tileData) {
|
||||
return result;
|
||||
}
|
||||
std::vector<IndexedSubfeature> sortedFeatures(symbolFeatures.begin(), symbolFeatures.end());
|
||||
std::vector<std::reference_wrapper<const RefIndexedSubfeature>> sortedFeatures(symbolFeatures.begin(),
|
||||
symbolFeatures.end());
|
||||
|
||||
std::sort(sortedFeatures.begin(),
|
||||
sortedFeatures.end(),
|
||||
[featureSortOrder](const IndexedSubfeature& a, const IndexedSubfeature& b) {
|
||||
[featureSortOrder](const RefIndexedSubfeature& a, const RefIndexedSubfeature& b) {
|
||||
// Same idea as the non-symbol sort order, but symbol features may
|
||||
// have changed their sort order since their corresponding
|
||||
// IndexedSubfeature was added to the CollisionIndex The
|
||||
@@ -124,15 +219,15 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
|
||||
// "top-to-bottom" rendering order (aka last-to-first).
|
||||
// Actually there can be multiple symbol instances per feature, so
|
||||
// we sort each feature based on the first matching symbol instance.
|
||||
auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.index);
|
||||
auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.index);
|
||||
auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.getIndex());
|
||||
auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.getIndex());
|
||||
assert(sortedA != featureSortOrder->end());
|
||||
assert(sortedB != featureSortOrder->end());
|
||||
return sortedA > sortedB;
|
||||
} else {
|
||||
// Bucket hasn't been re-sorted based on angle, so use same
|
||||
// "reverse of appearance in source data" logic as non-symboles
|
||||
return a.sortIndex > b.sortIndex;
|
||||
return a.getSortIndex() > b.getSortIndex();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -153,7 +248,7 @@ std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbol
|
||||
}
|
||||
|
||||
void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Feature>>& result,
|
||||
const IndexedSubfeature& indexedFeature,
|
||||
const RefIndexedSubfeature& indexedFeature,
|
||||
const RenderedQueryOptions& options,
|
||||
const CanonicalTileID& tileID,
|
||||
const std::unordered_map<std::string, const RenderLayer*>& layers,
|
||||
@@ -166,7 +261,7 @@ void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Featur
|
||||
std::unique_ptr<GeometryTileLayer> sourceLayer;
|
||||
std::unique_ptr<GeometryTileFeature> geometryTileFeature;
|
||||
|
||||
for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketLeaderID)) {
|
||||
for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.getBucketLeaderID())) {
|
||||
const auto it = layers.find(layerID);
|
||||
if (it == layers.end()) {
|
||||
continue;
|
||||
@@ -175,10 +270,10 @@ void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Featur
|
||||
const RenderLayer* renderLayer = it->second;
|
||||
|
||||
if (!geometryTileFeature) {
|
||||
sourceLayer = tileData->getLayer(indexedFeature.sourceLayerName);
|
||||
sourceLayer = tileData->getLayer(indexedFeature.getSourceLayerName());
|
||||
assert(sourceLayer);
|
||||
|
||||
geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
|
||||
geometryTileFeature = sourceLayer->getFeature(indexedFeature.getIndex());
|
||||
assert(geometryTileFeature);
|
||||
}
|
||||
FeatureState state;
|
||||
@@ -226,6 +321,8 @@ std::optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(const Ge
|
||||
}
|
||||
|
||||
GeometryCoordinates translated;
|
||||
translated.reserve(queryGeometry.size());
|
||||
|
||||
for (const auto& p : queryGeometry) {
|
||||
translated.push_back(p - translateVec);
|
||||
}
|
||||
@@ -233,6 +330,9 @@ std::optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(const Ge
|
||||
}
|
||||
|
||||
void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs) {
|
||||
if (bucketLayerIDs.empty()) {
|
||||
bucketLayerIDs.reserve(expectedUniqueLeaderIDs);
|
||||
}
|
||||
bucketLayerIDs[bucketLeaderID] = layerIDs;
|
||||
}
|
||||
|
||||
@@ -249,6 +349,7 @@ void DynamicFeatureIndex::query(std::unordered_map<std::string, std::vector<Feat
|
||||
const Point<int64_t> coord = {int64_t(pm.x), int64_t(pm.y)};
|
||||
mbgl::updateBBox(queryBox, coord);
|
||||
}
|
||||
|
||||
for (const auto& f : features) {
|
||||
// hit testing
|
||||
mbgl::GeometryBBox<int64_t> featureBox = DefaultWithinBBox;
|
||||
|
||||
@@ -21,34 +21,69 @@ class SourceFeatureState;
|
||||
|
||||
class CollisionIndex;
|
||||
|
||||
class IndexedSubfeature {
|
||||
/// An indexed element within a feature index.
|
||||
/// This version holds a reference to the strings within the index itself to avoid making tens of thousands of
|
||||
/// unnecessary copies of them. As a result, its lifetime cannot exceed that of the index.
|
||||
class RefIndexedSubfeature {
|
||||
public:
|
||||
IndexedSubfeature() = delete;
|
||||
IndexedSubfeature(std::size_t index_, std::string sourceLayerName_, std::string bucketName_, size_t sortIndex_)
|
||||
: index(index_),
|
||||
sourceLayerName(std::move(sourceLayerName_)),
|
||||
bucketLeaderID(std::move(bucketName_)),
|
||||
sortIndex(sortIndex_),
|
||||
bucketInstanceId(0),
|
||||
collisionGroupId(0) {}
|
||||
RefIndexedSubfeature() = delete;
|
||||
RefIndexedSubfeature(RefIndexedSubfeature&&) = default;
|
||||
RefIndexedSubfeature(const RefIndexedSubfeature&) = default;
|
||||
RefIndexedSubfeature(std::size_t index_,
|
||||
const std::string& sourceLayerName_,
|
||||
const std::string& bucketName_,
|
||||
size_t sortIndex_,
|
||||
uint32_t bucketInstanceId_ = 0,
|
||||
uint16_t collisionGroupId_ = 0);
|
||||
|
||||
IndexedSubfeature(const IndexedSubfeature& other, uint32_t bucketInstanceId_, uint16_t collisionGroupId_)
|
||||
: index(other.index),
|
||||
sourceLayerName(other.sourceLayerName),
|
||||
bucketLeaderID(other.bucketLeaderID),
|
||||
sortIndex(other.sortIndex),
|
||||
bucketInstanceId(bucketInstanceId_),
|
||||
collisionGroupId(collisionGroupId_) {}
|
||||
RefIndexedSubfeature& operator=(const RefIndexedSubfeature&) = default;
|
||||
RefIndexedSubfeature& operator=(RefIndexedSubfeature&&) = default;
|
||||
|
||||
size_t getIndex() const { return index; }
|
||||
size_t getSortIndex() const { return sortIndex; }
|
||||
|
||||
const std::string& getSourceLayerName() const { return sourceLayerName.get(); }
|
||||
const std::string& getBucketLeaderID() const { return bucketLeaderID.get(); }
|
||||
|
||||
uint32_t getBucketInstanceId() const { return bucketInstanceId; }
|
||||
uint16_t getCollisionGroupId() const { return collisionGroupId; }
|
||||
|
||||
protected:
|
||||
size_t index;
|
||||
std::string sourceLayerName;
|
||||
std::string bucketLeaderID;
|
||||
size_t sortIndex;
|
||||
|
||||
std::reference_wrapper<const std::string> sourceLayerName;
|
||||
std::reference_wrapper<const std::string> bucketLeaderID;
|
||||
|
||||
// Only used for symbol features
|
||||
uint32_t bucketInstanceId;
|
||||
uint16_t collisionGroupId;
|
||||
};
|
||||
|
||||
/// This version of an indexed feature has copies of the necessary strings, so that it can be used outside the index.
|
||||
class IndexedSubfeature : public RefIndexedSubfeature {
|
||||
public:
|
||||
IndexedSubfeature(const RefIndexedSubfeature&);
|
||||
IndexedSubfeature(const RefIndexedSubfeature&, uint32_t bucketInstanceId_, uint16_t collisionGroupId_);
|
||||
|
||||
IndexedSubfeature(const IndexedSubfeature&);
|
||||
IndexedSubfeature(IndexedSubfeature&&);
|
||||
|
||||
IndexedSubfeature(std::size_t index_,
|
||||
std::string sourceLayerName_,
|
||||
std::string bucketName_,
|
||||
size_t sortIndex_,
|
||||
uint32_t bucketInstanceId_ = 0,
|
||||
uint16_t collisionGroupId_ = 0);
|
||||
|
||||
IndexedSubfeature& operator=(const IndexedSubfeature&);
|
||||
IndexedSubfeature& operator=(IndexedSubfeature&&);
|
||||
|
||||
private:
|
||||
std::string sourceLayerNameCopy;
|
||||
std::string bucketLeaderIDCopy;
|
||||
};
|
||||
|
||||
using FeatureSortOrder = std::shared_ptr<const std::vector<size_t>>;
|
||||
|
||||
class DynamicFeatureIndex {
|
||||
@@ -112,7 +147,7 @@ public:
|
||||
|
||||
private:
|
||||
void addFeature(std::unordered_map<std::string, std::vector<Feature>>& result,
|
||||
const IndexedSubfeature&,
|
||||
const RefIndexedSubfeature&,
|
||||
const RenderedQueryOptions& options,
|
||||
const CanonicalTileID&,
|
||||
const std::unordered_map<std::string, const RenderLayer*>&,
|
||||
@@ -122,10 +157,15 @@ private:
|
||||
const mat4& posMatrix,
|
||||
const SourceFeatureState* sourceFeatureState) const;
|
||||
|
||||
GridIndex<IndexedSubfeature> grid;
|
||||
GridIndex<RefIndexedSubfeature> grid;
|
||||
unsigned int sortIndex = 0;
|
||||
|
||||
// mbgl::unordered_* cannot be used here, as we rely on holding references to elements:
|
||||
// 22.2.7 Unordered associative containers [unord.req]
|
||||
// The insert and emplace members shall not affect the validity of references to
|
||||
// container elements, but may invalidate all iterators to the container.
|
||||
std::unordered_map<std::string, std::vector<std::string>> bucketLayerIDs;
|
||||
std::unordered_set<std::string> uniqueLayerIDs;
|
||||
std::unique_ptr<const GeometryTileData> tileData;
|
||||
};
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -87,7 +87,7 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
|
||||
const float iconBoxScale,
|
||||
const float iconPadding,
|
||||
const std::array<float, 2>& iconOffset_,
|
||||
const IndexedSubfeature& indexedFeature,
|
||||
const RefIndexedSubfeature& indexedFeature,
|
||||
const std::size_t layoutFeatureIndex_,
|
||||
const std::size_t dataFeatureIndex_,
|
||||
std::u16string key_,
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
float iconBoxScale,
|
||||
float iconPadding,
|
||||
const std::array<float, 2>& iconOffset,
|
||||
const IndexedSubfeature& indexedFeature,
|
||||
const RefIndexedSubfeature& indexedFeature,
|
||||
std::size_t layoutFeatureIndex,
|
||||
std::size_t dataFeatureIndex,
|
||||
std::u16string key,
|
||||
|
||||
@@ -1206,13 +1206,15 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
// We'll be processing renderables across tiles, potentially out-of-order, so keep
|
||||
// track of some things by tile ID so we don't have to re-build them multiple times.
|
||||
using RawVertexVec = std::vector<std::uint8_t>; // <int16_t, 4>
|
||||
using RawVertexVec = std::vector<std::uint8_t>; // raw buffer for vertexes of <int16_t, 4>
|
||||
struct TileInfo {
|
||||
RawVertexVec textVertices, iconVertices;
|
||||
gfx::DrawableTweakerPtr textTweaker, iconTweaker;
|
||||
gfx::UniformBufferPtr textInterp, iconInterp;
|
||||
};
|
||||
|
||||
std::unordered_map<UnwrappedTileID, TileInfo> tileCache;
|
||||
tileCache.reserve(renderTiles->size());
|
||||
|
||||
for (auto& group : renderableSegments) {
|
||||
const auto& renderable = group.renderable;
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
const float boxScale,
|
||||
const float padding,
|
||||
const style::SymbolPlacementType placement,
|
||||
const IndexedSubfeature& indexedFeature_,
|
||||
const RefIndexedSubfeature& indexedFeature_,
|
||||
const float overscaling,
|
||||
const float rotate)
|
||||
: CollisionFeature(line,
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
std::optional<PositionedIcon> shapedIcon,
|
||||
const float boxScale,
|
||||
const float padding,
|
||||
const IndexedSubfeature& indexedFeature_,
|
||||
const RefIndexedSubfeature& indexedFeature_,
|
||||
const float rotate)
|
||||
: CollisionFeature(line,
|
||||
anchor,
|
||||
|
||||
@@ -159,7 +159,7 @@ std::pair<bool, bool> CollisionIndex::placeFeature(
|
||||
const bool pitchWithMap,
|
||||
const bool collisionDebug,
|
||||
const std::optional<CollisionBoundaries>& avoidEdges,
|
||||
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
std::vector<ProjectedCollisionBox>& projectedBoxes) {
|
||||
assert(projectedBoxes.empty());
|
||||
if (!feature.alongLine) {
|
||||
@@ -202,7 +202,7 @@ std::pair<bool, bool> CollisionIndex::placeLineFeature(
|
||||
const bool pitchWithMap,
|
||||
const bool collisionDebug,
|
||||
const std::optional<CollisionBoundaries>& avoidEdges,
|
||||
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
std::vector<ProjectedCollisionBox>& projectedBoxes) {
|
||||
assert(feature.alongLine);
|
||||
assert(projectedBoxes.empty());
|
||||
@@ -340,10 +340,10 @@ void CollisionIndex::insertFeature(const CollisionFeature& feature,
|
||||
}
|
||||
|
||||
if (ignorePlacement) {
|
||||
ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
|
||||
ignoredGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
|
||||
circle.circle());
|
||||
} else {
|
||||
collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
|
||||
collisionGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
|
||||
circle.circle());
|
||||
}
|
||||
}
|
||||
@@ -352,10 +352,10 @@ void CollisionIndex::insertFeature(const CollisionFeature& feature,
|
||||
auto& box = projectedBoxes[0];
|
||||
assert(box.isBox());
|
||||
if (ignorePlacement) {
|
||||
ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
|
||||
ignoredGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
|
||||
box.box());
|
||||
} else {
|
||||
collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
|
||||
collisionGrid.insert(IndexedSubfeature{feature.indexedFeature, bucketInstanceId, collisionGroupId},
|
||||
box.box());
|
||||
}
|
||||
}
|
||||
@@ -398,23 +398,25 @@ std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> CollisionIndex::que
|
||||
|
||||
std::vector<QueryResult> features = collisionGrid.queryWithBoxes(envelope);
|
||||
std::vector<QueryResult> ignoredFeatures = ignoredGrid.queryWithBoxes(envelope);
|
||||
features.insert(features.end(), ignoredFeatures.begin(), ignoredFeatures.end());
|
||||
features.insert(features.end(),
|
||||
std::make_move_iterator(ignoredFeatures.begin()),
|
||||
std::make_move_iterator(ignoredFeatures.end()));
|
||||
|
||||
std::unordered_map<uint32_t, std::unordered_set<size_t>> seenBuckets;
|
||||
mbgl::unordered_map<uint32_t, mbgl::unordered_set<size_t>> seenBuckets;
|
||||
for (auto& queryResult : features) {
|
||||
auto& feature = queryResult.first;
|
||||
auto& bbox = queryResult.second;
|
||||
|
||||
// Skip already seen features.
|
||||
auto& seenFeatures = seenBuckets[feature.bucketInstanceId];
|
||||
if (seenFeatures.find(feature.index) != seenFeatures.end()) continue;
|
||||
auto& seenFeatures = seenBuckets[feature.getBucketInstanceId()];
|
||||
if (seenFeatures.find(feature.getIndex()) != seenFeatures.end()) continue;
|
||||
|
||||
if (!polygonIntersectsBox(gridQuery, bbox)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seenFeatures.insert(feature.index);
|
||||
result[feature.bucketInstanceId].push_back(feature);
|
||||
seenFeatures.insert(feature.getIndex());
|
||||
result[feature.getBucketInstanceId()].push_back(feature);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
bool pitchWithMap,
|
||||
bool collisionDebug,
|
||||
const std::optional<CollisionBoundaries>& avoidEdges,
|
||||
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
std::vector<ProjectedCollisionBox>& /*out*/
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
bool pitchWithMap,
|
||||
bool collisionDebug,
|
||||
const std::optional<CollisionBoundaries>& avoidEdges,
|
||||
const std::optional<std::function<bool(const IndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
const std::optional<std::function<bool(const RefIndexedSubfeature&)>>& collisionGroupPredicate,
|
||||
std::vector<ProjectedCollisionBox>& /*out*/
|
||||
);
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& s
|
||||
collisionGroups.emplace(
|
||||
sourceID,
|
||||
CollisionGroup(nextGroupID,
|
||||
std::optional<Predicate>([nextGroupID](const IndexedSubfeature& feature) -> bool {
|
||||
return feature.collisionGroupId == nextGroupID;
|
||||
std::optional<Predicate>([nextGroupID](const RefIndexedSubfeature& feature) -> bool {
|
||||
return feature.getCollisionGroupId() == nextGroupID;
|
||||
})));
|
||||
}
|
||||
return collisionGroups[sourceID];
|
||||
|
||||
@@ -77,7 +77,7 @@ struct RetainedQueryData {
|
||||
|
||||
class CollisionGroups {
|
||||
public:
|
||||
using Predicate = std::function<bool(const IndexedSubfeature&)>;
|
||||
using Predicate = std::function<bool(const RefIndexedSubfeature&)>;
|
||||
using CollisionGroup = std::pair<uint16_t, std::optional<Predicate>>;
|
||||
|
||||
CollisionGroups(const bool crossSourceCollisions_)
|
||||
|
||||
@@ -363,7 +363,9 @@ void GeometryTileWorker::parse() {
|
||||
ImageDependencies imageDependencies;
|
||||
|
||||
// Create render layers and group by layout
|
||||
std::unordered_map<std::string, std::vector<Immutable<style::LayerProperties>>> groupMap;
|
||||
mbgl::unordered_map<std::string, std::vector<Immutable<style::LayerProperties>>> groupMap;
|
||||
groupMap.reserve(layers->size());
|
||||
|
||||
for (auto layer : *layers) {
|
||||
groupMap[layoutKey(*layer->baseImpl)].push_back(std::move(layer));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template class GridIndex<IndexedSubfeature>;
|
||||
template class GridIndex<RefIndexedSubfeature>;
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -141,7 +141,7 @@ void GridIndex<T>::insert(T&& t, const BBox& bbox) {
|
||||
}
|
||||
}
|
||||
|
||||
boxElements.emplace_back(t, bbox);
|
||||
boxElements.emplace_back(std::move(t), bbox);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -164,7 +164,7 @@ void GridIndex<T>::insert(T&& t, const BCircle& bcircle) {
|
||||
}
|
||||
}
|
||||
|
||||
circleElements.emplace_back(t, bcircle);
|
||||
circleElements.emplace_back(std::move(t), bcircle);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -10,7 +10,7 @@ SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) {
|
||||
ImageMap imageMap;
|
||||
const ShapedTextOrientations shaping{};
|
||||
style::SymbolLayoutProperties::Evaluated layout_;
|
||||
IndexedSubfeature subfeature(0, "", "", 0);
|
||||
IndexedSubfeature subfeature(0, {}, {}, 0);
|
||||
Anchor anchor(x, y, 0, 0);
|
||||
std::array<float, 2> textOffset{{0.0f, 0.0f}};
|
||||
std::array<float, 2> iconOffset{{0.0f, 0.0f}};
|
||||
|
||||
Reference in New Issue
Block a user