#include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { // static Immutable GeoJSONOptions::defaultOptions() { static Immutable options = makeMutable(); return options; } GeoJSONSource::GeoJSONSource(std::string id, Immutable options) : Source(makeMutable(std::move(id), std::move(options))), threadPool(Scheduler::GetBackground()) {} GeoJSONSource::~GeoJSONSource() = default; const GeoJSONSource::Impl& GeoJSONSource::impl() const { return static_cast(*baseImpl); } void GeoJSONSource::setURL(const std::string& url_) { url = url_; // Signal that the source description needs a reload if (loaded || req) { loaded = false; req.reset(); observer->onSourceDescriptionChanged(*this); } } void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) { setGeoJSONData(GeoJSONData::create(geoJSON, impl().getOptions())); } void GeoJSONSource::setGeoJSONData(std::shared_ptr geoJSONData) { req.reset(); baseImpl = makeMutable(impl(), std::move(geoJSONData)); observer->onSourceChanged(*this); } optional GeoJSONSource::getURL() const { return url; } const GeoJSONOptions& GeoJSONSource::getOptions() const { return *impl().getOptions(); } void GeoJSONSource::loadDescription(FileSource& fileSource) { if (!url) { loaded = true; return; } if (req) { return; } req = fileSource.request(Resource::source(*url), [this](Response res) { if (res.error) { observer->onSourceError( *this, std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified) { return; } else if (res.noContent) { observer->onSourceError( *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); } else { auto makeImplInBackground = [currentImpl = baseImpl, data = res.data]() -> Immutable { assert(data); auto& impl = static_cast(*currentImpl); conversion::Error error; std::shared_ptr geoJSONData; if (optional geoJSON = conversion::convertJSON(*data, error)) { geoJSONData = GeoJSONData::create(*geoJSON, impl.getOptions()); } else { // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load. Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", error.message.c_str()); } return makeMutable(impl, std::move(geoJSONData)); }; auto onImplReady = [this, self = makeWeakPtr(), capturedReq = req.get()](Immutable newImpl) { assert(capturedReq); if (!self) return; // This source has been deleted. if (capturedReq != req.get()) return; // A new request is being processed, ignore this impl. baseImpl = std::move(newImpl); loaded = true; observer->onSourceLoaded(*this); }; threadPool->scheduleAndReplyValue(makeImplInBackground, onImplReady); } }); } bool GeoJSONSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const { return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind); } } // namespace style } // namespace mbgl