#include #include #include #include #include #include namespace mbgl { RenderLineLayer::RenderLineLayer(const style::LineLayer::Impl& _impl) : RenderLayer(style::LayerType::Line, _impl), impl(&_impl) { } std::unique_ptr RenderLineLayer::clone() const { return std::make_unique(*this); } std::unique_ptr RenderLineLayer::createBucket(const BucketParameters& parameters, const std::vector& layers) const { return std::make_unique(parameters, layers, impl->layout); } void RenderLineLayer::cascade(const style::CascadeParameters& parameters) { unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); } bool RenderLineLayer::evaluate(const style::PropertyEvaluationParameters& parameters) { // for scaling dasharrays auto dashArrayParams = parameters; dashArrayParams.z = std::floor(dashArrayParams.z); dashLineWidth = unevaluated.evaluate(dashArrayParams); evaluated = unevaluated.evaluate(parameters); passes = (evaluated.get().constantOr(1.0) > 0 && evaluated.get().constantOr(Color::black()).a > 0 && evaluated.get() > 0) ? RenderPass::Translucent : RenderPass::None; return unevaluated.hasTransition(); } optional offsetLine(const GeometryCollection& rings, const double offset) { if (offset == 0) return {}; GeometryCollection newRings; Point zero(0, 0); for (const auto& ring : rings) { newRings.emplace_back(); auto& newRing = newRings.back(); for (auto i = ring.begin(); i != ring.end(); i++) { auto& p = *i; Point aToB = i == ring.begin() ? zero : util::perp(util::unit(convertPoint(p - *(i - 1)))); Point bToC = i + 1 == ring.end() ? zero : util::perp(util::unit(convertPoint(*(i + 1) - p))); Point extrude = util::unit(aToB + bToC); const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y; extrude *= (1.0 / cosHalfAngle); newRing.push_back(convertPoint(extrude * offset) + p); } } return newRings; } bool RenderLineLayer::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, const GeometryTileFeature& feature, const float zoom, const float bearing, const float pixelsToTileUnits) const { // Translate query geometry auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, evaluated.get(), evaluated.get(), bearing, pixelsToTileUnits); // Evaluate function auto offset = evaluated.get() .evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits; // Apply offset to geometry auto offsetGeometry = offsetLine(feature.getGeometries(), offset); // Test intersection const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits; return util::polygonIntersectsBufferedMultiLine( translatedQueryGeometry.value_or(queryGeometry), offsetGeometry.value_or(feature.getGeometries()), halfWidth); } float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const { float lineWidth = evaluated.get(); float gapWidth = evaluated.get() .evaluate(feature, zoom, style::LineGapWidth::defaultValue()); if (gapWidth) { return gapWidth + 2 * lineWidth; } else { return lineWidth; } } } // namespace mbgl