Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

expose annotation styling #1820

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions include/mbgl/annotation/shape_annotation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace mbgl {

class ShapeAnnotation {
public:
inline ShapeAnnotation(const AnnotationSegments& segments_, const StyleProperties& styleProperties_)
: segments(segments_), styleProperties(styleProperties_) {
inline ShapeAnnotation(const AnnotationSegments& segments_, const AnnotationStyle& style_)
: segments(segments_), style(style_) {
}

const AnnotationSegments segments;
const StyleProperties styleProperties;
const AnnotationStyle style;
};

}
Expand Down
6 changes: 6 additions & 0 deletions include/mbgl/ios/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ IB_DESIGNABLE
* @return A line width for the polyline. */
- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;

/** Returns the line join to use when rendering a polyline annotation. Defaults to `kCGLineJoinRound`. */
- (CGLineJoin)mapView:(MGLMapView *)mapView lineJoinForPolylineAnnotation:(MGLPolyline *)annotation;

/** Returns the line cap to use when rendering a polyline annotation. Defaults to `kCGLineCapButt`. */
- (CGLineCap)mapView:(MGLMapView *)mapView lineCapForPolylineAnnotation:(MGLPolyline *)annotation;

/** Returns a Boolean value indicating whether the annotation is able to display extra information in a callout bubble.
*
* If the value returned is `YES`, a standard callout bubble is shown when the user taps a selected annotation. The callout uses the title and subtitle text from the associated annotation object. If there is no title text, though, the annotation will not show a callout. The callout also displays any custom callout views returned by the delegate for the left and right callout accessory views.
Expand Down
4 changes: 4 additions & 0 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/map/update.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/style/property_key.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/vec.hpp>
Expand All @@ -13,6 +15,7 @@
#include <functional>
#include <vector>
#include <memory>
#include <map>

namespace mbgl {

Expand All @@ -38,6 +41,7 @@ enum class AnnotationType : uint8_t {
using AnnotationIDs = std::vector<uint32_t>;
using AnnotationSegment = std::vector<LatLng>;
using AnnotationSegments = std::vector<AnnotationSegment>;
using AnnotationStyle = std::map<PropertyKey, PropertyValue>;

using EdgeInsets = struct {
double top, left, bottom, right;
Expand Down
86 changes: 73 additions & 13 deletions platform/ios/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <mbgl/platform/darwin/reachability.h>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/style/function_properties.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/constants.hpp>

Expand Down Expand Up @@ -117,6 +118,16 @@ @implementation MGLMapView
return std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<float, std::chrono::seconds::period>(duration));
}

template <typename T>
mbgl::PropertyValue MGLShapeStyleConstantPropertyValue(T value)
{
mbgl::ConstantFunction<T> constantFunction(value);
mbgl::Function<T> function(constantFunction);
mbgl::PropertyValue result(function);

return result;
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
Expand Down Expand Up @@ -1797,6 +1808,8 @@ - (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
BOOL delegateImplementsStrokeColorForShape = [self.delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)];
BOOL delegateImplementsFillColorForPolygon = [self.delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)];
BOOL delegateImplementsLineWidthForPolyline = [self.delegate respondsToSelector:@selector(mapView:lineWidthForPolylineAnnotation:)];
BOOL delegateImplementsLineJoinForPolyline = [self.delegate respondsToSelector:@selector(mapView:lineJoinForPolylineAnnotation:)];
BOOL delegateImplementsLineCapForPolyline = [self.delegate respondsToSelector:@selector(mapView:lineCapForPolylineAnnotation:)];

for (id <MGLAnnotation> annotation in annotations)
{
Expand All @@ -1818,20 +1831,64 @@ - (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
[strokeColor getRed:&r green:&g blue:&b alpha:&a];
mbgl::Color strokeNativeColor({{ (float)r, (float)g, (float)b, (float)a }});

mbgl::StyleProperties shapeProperties;
mbgl::AnnotationStyle shapeStyle;

if ([annotation isKindOfClass:[MGLPolyline class]])
{
CGFloat lineWidth = (delegateImplementsLineWidthForPolyline ?
CGFloat width = (delegateImplementsLineWidthForPolyline ?
[self.delegate mapView:self lineWidthForPolylineAnnotation:(MGLPolyline *)annotation] :
3.0);

mbgl::LineProperties lineProperties;
lineProperties.opacity = alpha;
lineProperties.color = strokeNativeColor;
lineProperties.width = lineWidth;
shapeProperties.set<mbgl::LineProperties>(lineProperties);
shapeStyle.emplace(mbgl::PropertyKey::LineOpacity,
MGLShapeStyleConstantPropertyValue(float(alpha)));

shapeStyle.emplace(mbgl::PropertyKey::LineColor,
MGLShapeStyleConstantPropertyValue(strokeNativeColor));

shapeStyle.emplace(mbgl::PropertyKey::LineWidth,
MGLShapeStyleConstantPropertyValue(float(width)));

if (delegateImplementsLineJoinForPolyline)
{
CGLineJoin lineJoin = [self.delegate mapView:self lineJoinForPolylineAnnotation:(MGLPolyline *)annotation];

if (lineJoin == kCGLineJoinBevel)
{
shapeStyle.emplace(mbgl::PropertyKey::LineJoin,
MGLShapeStyleConstantPropertyValue(mbgl::JoinType::Bevel));
}
else if (lineJoin == kCGLineJoinMiter)
{
shapeStyle.emplace(mbgl::PropertyKey::LineJoin,
MGLShapeStyleConstantPropertyValue(mbgl::JoinType::Miter));
}
else if (lineJoin == kCGLineJoinRound)
{
shapeStyle.emplace(mbgl::PropertyKey::LineJoin,
MGLShapeStyleConstantPropertyValue(mbgl::JoinType::Round));
}
}

if (delegateImplementsLineCapForPolyline)
{
CGLineCap lineCap = [self.delegate mapView:self lineCapForPolylineAnnotation:(MGLPolyline *)annotation];

if (lineCap == kCGLineCapButt)
{
shapeStyle.emplace(mbgl::PropertyKey::LineCap,
MGLShapeStyleConstantPropertyValue(mbgl::CapType::Butt));
}
else if (lineCap == kCGLineCapRound)
{
shapeStyle.emplace(mbgl::PropertyKey::LineCap,
MGLShapeStyleConstantPropertyValue(mbgl::CapType::Round));
}
else if (lineCap == kCGLineCapSquare)
{
shapeStyle.emplace(mbgl::PropertyKey::LineCap,
MGLShapeStyleConstantPropertyValue(mbgl::CapType::Square));
}
}
}
else if ([annotation isKindOfClass:[MGLPolygon class]])
{
Expand All @@ -1844,11 +1901,14 @@ - (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
[fillColor getRed:&r green:&g blue:&b alpha:&a];
mbgl::Color fillNativeColor({{ (float)r, (float)g, (float)b, (float)a }});

mbgl::FillProperties fillProperties;
fillProperties.opacity = alpha;
fillProperties.stroke_color = strokeNativeColor;
fillProperties.fill_color = fillNativeColor;
shapeProperties.set<mbgl::FillProperties>(fillProperties);
shapeStyle.emplace(mbgl::PropertyKey::FillOpacity,
MGLShapeStyleConstantPropertyValue(float(alpha)));

shapeStyle.emplace(mbgl::PropertyKey::FillOutlineColor,
MGLShapeStyleConstantPropertyValue(strokeNativeColor));

shapeStyle.emplace(mbgl::PropertyKey::FillColor,
MGLShapeStyleConstantPropertyValue(fillNativeColor));
}
else
{
Expand All @@ -1872,7 +1932,7 @@ - (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations

free(coordinates);

shapes.emplace_back(mbgl::AnnotationSegments {{ segment }}, shapeProperties);
shapes.emplace_back(mbgl::AnnotationSegments {{ segment }}, shapeStyle);
}
else
{
Expand Down
69 changes: 15 additions & 54 deletions src/mbgl/map/annotation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace mbgl {

Annotation::Annotation(AnnotationType type_,
const AnnotationSegments& geometry_,
const StyleProperties& styleProperties_)
: styleProperties(styleProperties_),
const AnnotationStyle& style_)
: style(style_),
type(type_),
geometry(geometry_),
bounds([this] {
Expand Down Expand Up @@ -83,15 +83,15 @@ AnnotationManager::addTileFeature(const uint32_t annotationID,
const AnnotationSegments& segments,
const std::vector<std::vector<vec2<double>>>& projectedFeature,
const AnnotationType& type,
const StyleProperties& styleProperties,
const AnnotationStyle& style,
const std::unordered_map<std::string, std::string>& featureProperties,
const uint8_t maxZoom) {

assert(type != AnnotationType::Any);

// track the annotation global ID and its original geometry
auto anno_it = annotations.emplace(annotationID,
std::make_unique<Annotation>(type, segments, styleProperties));
std::make_unique<Annotation>(type, segments, style));

std::unordered_set<TileID, TileID::Hash> affectedTiles;

Expand All @@ -118,7 +118,7 @@ AnnotationManager::addTileFeature(const uint32_t annotationID,

ProjectedFeatureType featureType;

if (styleProperties.is<FillProperties>()) {
if (style.find(PropertyKey::FillColor) != style.end()) {
featureType = ProjectedFeatureType::Polygon;

if (points.front().lon != points.back().lon || points.front().lat != points.back().lat) {
Expand Down Expand Up @@ -152,60 +152,21 @@ AnnotationManager::addTileFeature(const uint32_t annotationID,

std::unordered_map<TileID, GeometryCollection, TileID::Hash> featureTiles;

if (type == AnnotationType::Point) {
auto& pp = projectedFeature[0][0];
auto& pp = projectedFeature[0][0];

x = pp.x * z2;
y = pp.y * z2;
x = pp.x * z2;
y = pp.y * z2;

const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));
const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));

GeometryCollection geometries = {{ {{ coordinate }} }};
GeometryCollection geometries = {{ {{ coordinate }} }};

featureTiles.emplace(TileID(z, x, y, z), geometries);
} else {
for (size_t l = 0; l < projectedFeature.size(); ++l) {

std::vector<Coordinate> line;

for (size_t p = 0; p < projectedFeature[l].size(); ++p) {

auto& pp = projectedFeature[l][p];

x = pp.x * z2;
y = pp.y * z2;

const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));

auto tile_it = featureTiles.find(TileID(z, x, y, z));

if (tile_it != featureTiles.end()) {
GeometryCollection& geometries = featureTiles.find(TileID(z, x, y, z))->second;
if (geometries.size()) {
geometries.back().push_back(coordinate);
} else {
geometries.push_back({{ coordinate }});
}
} else {
GeometryCollection geometries = {{ {{ coordinate }} }};
featureTiles.emplace(TileID(z, x, y, z), geometries);
}
}
}
}
featureTiles.emplace(TileID(z, x, y, z), geometries);

for (auto& featureTile : featureTiles) {
// determine feature type
FeatureType featureType;
if (type == AnnotationType::Point) {
featureType = FeatureType::Point;
} else if (styleProperties.is<LineProperties>()) {
featureType = FeatureType::LineString;
} else if (styleProperties.is<FillProperties>()) {
featureType = FeatureType::Polygon;
} else {
throw std::runtime_error("Invalid feature type");
}
featureType = FeatureType::Point;

// create tile feature
auto feature = std::make_shared<const LiveTileFeature>(
Expand Down Expand Up @@ -334,7 +295,7 @@ AnnotationManager::addShapeAnnotations(const std::vector<ShapeAnnotation>& shape
shape.segments,
{{ }},
AnnotationType::Shape,
shape.styleProperties,
shape.style,
{{ }},
maxZoom
);
Expand Down Expand Up @@ -415,13 +376,13 @@ std::unordered_set<TileID, TileID::Hash> AnnotationManager::removeAnnotations(co
return affectedTiles;
}

const StyleProperties AnnotationManager::getAnnotationStyleProperties(uint32_t annotationID) const {
const AnnotationStyle& AnnotationManager::getAnnotationStyle(uint32_t annotationID) const {
std::lock_guard<std::mutex> lock(mtx);

auto anno_it = annotations.find(annotationID);
assert(anno_it != annotations.end());

return anno_it->second->styleProperties;
return anno_it->second->style;
}

AnnotationIDs AnnotationManager::getAnnotationsInBounds(const LatLngBounds& queryBounds,
Expand Down
8 changes: 4 additions & 4 deletions src/mbgl/map/annotation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ using GeoJSONVT = mapbox::util::geojsonvt::GeoJSONVT;
class Annotation : private util::noncopyable {
friend class AnnotationManager;
public:
Annotation(AnnotationType, const AnnotationSegments&, const StyleProperties&);
Annotation(AnnotationType, const AnnotationSegments&, const AnnotationStyle&);

public:
const StyleProperties styleProperties;
const AnnotationStyle style;

private:
LatLng getPoint() const;
Expand Down Expand Up @@ -67,7 +67,7 @@ class AnnotationManager : private util::noncopyable {

std::unordered_set<TileID, TileID::Hash> removeAnnotations(const AnnotationIDs&, const uint8_t maxZoom);
AnnotationIDs getOrderedShapeAnnotations() const { return orderedShapeAnnotations; }
const StyleProperties getAnnotationStyleProperties(uint32_t) const;
const AnnotationStyle& getAnnotationStyle(uint32_t) const;

AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const uint8_t maxZoom, const AnnotationType& = AnnotationType::Any) const;
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const;
Expand All @@ -85,7 +85,7 @@ class AnnotationManager : private util::noncopyable {
const AnnotationSegments&,
const std::vector<std::vector<vec2<double>>>& projectedFeature,
const AnnotationType&,
const StyleProperties&,
const AnnotationStyle&,
const std::unordered_map<std::string, std::string>& featureProperties,
const uint8_t maxZoom);

Expand Down
Loading