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

Allow initializing MGLGeoJSONSource from a shape #7145

Merged
merged 1 commit into from
Dec 6, 2016
Merged
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
75 changes: 55 additions & 20 deletions platform/darwin/src/MGLFeature.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "NSExpression+MGLAdditions.h"

#import <mbgl/util/geometry.hpp>
#import <mbgl/style/conversion/geojson.hpp>
#import <mapbox/geometry/feature.hpp>

@interface MGLPointFeature () <MGLFeaturePrivate>
Expand All @@ -33,7 +34,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand All @@ -55,7 +56,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand All @@ -77,7 +78,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand All @@ -99,7 +100,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand All @@ -121,7 +122,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand All @@ -143,7 +144,7 @@ - (NSDictionary *)geoJSONDictionary {
}

- (mbgl::Feature)mbglFeature {
return mbglFeature([self featureObject], identifier, self.attributes);
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}

@end
Expand Down Expand Up @@ -266,27 +267,61 @@ static CLLocationCoordinate2D toLocationCoordinate2D(const mbgl::Point<T> &point
}
};

template <typename T>
class GeoJSONEvaluator {
public:
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Geometry<T> &geometry) const {
GeometryEvaluator<T> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<T>::visit(geometry, evaluator);
return shape;
}

MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Feature &feature) const {
GeometryEvaluator<T> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<T>::visit(feature.geometry, evaluator);
return shape;
}

MGLShape <MGLFeaturePrivate> * operator()(const mbgl::FeatureCollection &collection) const {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
for (const auto &feature : collection) {
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
}
return [MGLShapeCollection<MGLFeaturePrivate> shapeCollectionWithShapes:shapes];
}
};

NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
for (const auto &feature : features) {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
for (auto &pair : feature.properties) {
auto &value = pair.second;
ValueEvaluator evaluator;
attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
}

GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;
[shapes addObject:shape];
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
}
return shapes;
}

id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature) {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
for (auto &pair : feature.properties) {
auto &value = pair.second;
ValueEvaluator evaluator;
attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
}
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;

return shape;
}

MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson) {
GeoJSONEvaluator<double> evaluator;
MGLShape *shape = mapbox::geojson::geojson::visit(geojson, evaluator);
return shape;
}

mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes)
{
if (identifier) {
Expand Down
12 changes: 12 additions & 0 deletions platform/darwin/src/MGLFeature_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#import <mbgl/util/geo.hpp>
#import <mbgl/util/feature.hpp>
#import <mbgl/style/conversion/geojson.hpp>

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -12,6 +13,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);

/**
Returns an `MGLFeature` object converted from the given mbgl::Feature
*/
id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature);

/**
Returns an `MGLShape` representing the given geojson. The shape can be
a feature, a collection of features, or a geometry.
*/
MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson);

/**
Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and
returns the feature object with converted `mbgl::FeatureIdentifier` and
Expand Down
13 changes: 7 additions & 6 deletions platform/darwin/src/MGLGeoJSONSource.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "MGLSource.h"

#import "MGLTypes.h"
#import "MGLShape.h"

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -93,28 +94,29 @@ extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationToleranc
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;

/**
Returns a GeoJSON source with an identifier, features dictionary, and dictionary
Returns a GeoJSON source with an identifier, features dictionary, and dictionary
of options for the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.

@param identifier A string that uniquely identifies the source.
@param features An array of features that conform to the `MGLFeature` protocol.
@param shape A concrete subclass of `MGLShape`
@param options An `NSDictionary` of options for this source.
@return An initialized GeoJSON source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean to create a source from no shapes at all? It does work in the current release branch, using an empty array of features, but we should make sure it works when shape is nil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nil shape works but I can't think of any case where you'd want to do that.


#pragma mark Accessing a Source’s Content

/**
The contents of the source.
The contents of the source. A shape can represent a GeoJSON geometry, a feature,
or a collection of features.

If the receiver was initialized using `-initWithIdentifier:URL:options:`, this property
is set to `nil`. This property is unavailable until the receiver is passed into
`-[MGLStyle addSource]`.
*/
@property (nonatomic, nullable) NS_ARRAY_OF(id <MGLFeature>) *features;
@property (nonatomic, nullable) MGLShape *shape;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the documentation for this property.


/**
A GeoJSON representation of the contents of the source.
Expand All @@ -138,7 +140,6 @@ extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationToleranc
*/
@property (nonatomic, nullable) NSURL *URL;


@end

NS_ASSUME_NONNULL_END
43 changes: 17 additions & 26 deletions platform/darwin/src/MGLGeoJSONSource.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLFeature_Private.h"
#import "MGLShape_Private.h"

#import "NSURL+MGLAdditions.h"

Expand Down Expand Up @@ -49,13 +50,13 @@ - (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url optio
return self;
}

- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(NS_DICTIONARY_OF(NSString *,id) *)options {
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NSDictionary<MGLGeoJSONSourceOption,id> *)options
{
if (self = [super initWithIdentifier:identifier]) {
_features = features;
_shape = shape;
_options = options;
[self commonInit];
}

return self;
}

Expand Down Expand Up @@ -85,21 +86,15 @@ - (void)commonInit
if (self.URL) {
NSURL *url = self.URL.mgl_URLByStandardizingScheme;
source->setURL(url.absoluteString.UTF8String);
_features = nil;
_shape = nil;
} else if (self.geoJSONData) {
NSString *string = [[NSString alloc] initWithData:self.geoJSONData encoding:NSUTF8StringEncoding];
const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>();
const auto geojson = mapbox::geojson::parse(string.UTF8String);
source->setGeoJSON(geojson);
Copy link
Contributor Author

@frederoni frederoni Nov 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assign features here if we're gonna support plain geometries or a single feature. Would it make sense to rename features to geometries and write a GeoJSON evaluator which overloads featureCollection, feature and geometry?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a shape property that can be any MGLShape (or any MGLFeature). We can have a features property as a convenience for when shape happens to contain an MGLShapeCollectionFeature.

_features = MGLFeaturesFromMBGLFeatures(geojson);
_shape = MGLShapeFromGeoJSON(geojson);
} else {
mbgl::FeatureCollection featureCollection;
featureCollection.reserve(self.features.count);
for (id <MGLFeaturePrivate> feature in self.features) {
featureCollection.push_back([feature mbglFeature]);
}
const auto geojson = mbgl::GeoJSON{featureCollection};
const auto geojson = mbgl::GeoJSON{self.shape.geometryObject};
source->setGeoJSON(geojson);
_features = MGLFeaturesFromMBGLFeatures(featureCollection);
}

_pendingSource = std::move(source);
Expand Down Expand Up @@ -161,10 +156,10 @@ - (void)setGeoJSONData:(NSData *)geoJSONData
}

NSString *string = [[NSString alloc] initWithData:_geoJSONData encoding:NSUTF8StringEncoding];
const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>();
const auto geojson = mapbox::geojson::parse(string.UTF8String);
self.rawSource->setGeoJSON(geojson);

_features = MGLFeaturesFromMBGLFeatures(geojson);
_shape = MGLShapeFromGeoJSON(geojson);
}

- (void)setURL:(NSURL *)URL
Expand All @@ -180,28 +175,24 @@ - (void)setURL:(NSURL *)URL
self.rawSource->setURL(url.absoluteString.UTF8String);
}

- (void)setFeatures:(NSArray *)features

- (void)setShape:(MGLShape *)shape
{
if (self.rawSource == NULL)
{
[self commonInit];
}

mbgl::FeatureCollection featureCollection;
featureCollection.reserve(features.count);
for (id <MGLFeaturePrivate> feature in features) {
featureCollection.push_back([feature mbglFeature]);
}
const auto geojson = mbgl::GeoJSON{featureCollection};

const auto geojson = mbgl::GeoJSON{shape.geometryObject};
self.rawSource->setGeoJSON(geojson);

_features = MGLFeaturesFromMBGLFeatures(featureCollection);
_shape = shape;
}

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; geoJSONData = %@; features = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.geoJSONData, self.features];
return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; geoJSONData = %@; shape = %@>",
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.geoJSONData, self.shape];
}

@end
4 changes: 2 additions & 2 deletions platform/darwin/src/MGLPointAnnotation.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ - (NSDictionary *)geoJSONDictionary
@"coordinates": @[@(self.coordinate.longitude), @(self.coordinate.latitude)]};
}

- (mbgl::Feature)featureObject
- (mbgl::Geometry<double>)geometryObject
{
mbgl::Point<double> point = { self.coordinate.longitude, self.coordinate.latitude };
return mbgl::Feature {point};
return point;
}

@end
Expand Down
4 changes: 2 additions & 2 deletions platform/darwin/src/MGLPointCollection.mm
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}

- (mbgl::Feature)featureObject
- (mbgl::Geometry<double>)geometryObject
{
mbgl::MultiPoint<double> multiPoint;
multiPoint.reserve(self.pointCount);
for (NSInteger i = 0; i< self.pointCount; i++)
{
multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude));
}
return mbgl::Feature {multiPoint};
return multiPoint;
}

- (NSDictionary *)geoJSONDictionary
Expand Down
21 changes: 10 additions & 11 deletions platform/darwin/src/MGLPolygon.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,22 @@ - (instancetype)initWithCoordinates:(const CLLocationCoordinate2D *)coords count
return result;
}

- (mbgl::Feature)featureObject {
- (mbgl::Polygon<double>)polygon {
mbgl::Polygon<double> geometry;
geometry.push_back(self.ring);
for (MGLPolygon *polygon in self.interiorPolygons) {
geometry.push_back(polygon.ring);
}
return mbgl::Feature{geometry};
return geometry;
}

- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
mbgl::Polygon<double> geometry;
geometry.push_back(self.ring);
for (MGLPolygon *polygon in self.interiorPolygons) {
geometry.push_back(polygon.ring);
}
- (mbgl::Geometry<double>)geometryObject {
return [self polygon];
}

mbgl::FillAnnotation annotation { geometry };
- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {

mbgl::FillAnnotation annotation { [self polygon] };
annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) };
annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] };
annotation.color = { [delegate fillColorForPolygonAnnotation:self] };
Expand Down Expand Up @@ -103,7 +102,7 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}

- (mbgl::Feature)featureObject {
- (mbgl::Geometry<double>)geometryObject {
mbgl::MultiPolygon<double> multiPolygon;
multiPolygon.reserve(self.polygons.count);
for (MGLPolygon *polygon in self.polygons) {
Expand All @@ -114,7 +113,7 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
}
multiPolygon.push_back(geometry);
}
return mbgl::Feature {multiPolygon};
return multiPolygon;
}

- (NSDictionary *)geoJSONDictionary {
Expand Down
Loading