Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios): add cutout circle API #677

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion android/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# this is your module manifest and used by Titanium
# during compilation, packaging, distribution, etc.
#
version: 5.6.1
version: 5.7.0
apiversion: 4
architectures: arm64-v8a armeabi-v7a x86 x86_64
description: External version of Map module using native Google Maps library
Expand Down
1 change: 1 addition & 0 deletions android/src/ti/map/MapModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class MapModule extends KrollModule implements OnMapsSdkInitializedCallba
public static final String PROPERTY_STROKE_COLOR = "strokeColor";
public static final String PROPERTY_STROKE_WIDTH = "strokeWidth";
public static final String PROPERTY_FILL_COLOR = "fillColor";
public static final String PROPERTY_OVERLAY_COLOR = "overlayColor";
public static final String PROPERTY_ZINDEX = "zIndex";
public static final String PROPERTY_POLYGON = "polygon";
public static final String PROPERTY_POLYGONS = "polygons";
Expand Down
37 changes: 37 additions & 0 deletions android/src/ti/map/TiMapUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,41 @@ public static ArrayList<LatLng> processPoints(Object points)
}
return locationArray;
}

public static List<LatLng> createOuterBounds() {
float delta = 0.01f;

return new ArrayList<LatLng>() {{
add(new LatLng(90 - delta, -180 + delta));
add(new LatLng(0, -180 + delta));
add(new LatLng(-90 + delta, -180 + delta));
add(new LatLng(-90 + delta, 0));
add(new LatLng(-90 + delta, 180 - delta));
add(new LatLng(0, 180 - delta));
add(new LatLng(90 - delta, 180 - delta));
add(new LatLng(90 - delta, 0));
add(new LatLng(90 - delta, -180 + delta));
}};
}

public static Iterable<LatLng> createHole(LatLng center, int radius) {
int points = 50; // number of corners of inscribed polygon

double radiusLatitude = Math.toDegrees(radius / 1000 / 6371.0);
double radiusLongitude = radiusLatitude / Math.cos(Math.toRadians(center.latitude));

List<LatLng> result = new ArrayList<>(points);

double anglePerCircleRegion = 2 * Math.PI / points;

for (int i = 0; i < points; i++) {
double theta = i * anglePerCircleRegion;
double latitude = center.latitude + (radiusLatitude * Math.sin(theta));
double longitude = center.longitude + (radiusLongitude * Math.cos(theta));

result.add(new LatLng(latitude, longitude));
}

return result;
}
}
31 changes: 31 additions & 0 deletions android/src/ti/map/TiUIMapView.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

package ti.map;

import static ti.map.TiMapUtils.createHole;
import static ti.map.TiMapUtils.createOuterBounds;
import static ti.map.TiMapUtils.parseLocation;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
Expand Down Expand Up @@ -34,6 +38,7 @@
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MapStyleOptions;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterManager;
Expand Down Expand Up @@ -894,6 +899,32 @@ public void removeAllPolylines()
currentPolylines.clear();
}

/**
* Cutout Circle
*/
protected void addCutoutCircle(KrollDict circleConfig) {
if (map == null) {
return;
}

Activity currentActivity = TiApplication.getAppCurrentActivity();

LatLng center = parseLocation(circleConfig);
int radius = circleConfig.getInt(MapModule.PROPERTY_RADIUS);
float strokeWidth = circleConfig.getDouble(MapModule.PROPERTY_STROKE_WIDTH).floatValue();
int strokeColor = TiConvert.toColor(circleConfig.getString(MapModule.PROPERTY_STROKE_COLOR), currentActivity);
int overlayColor = TiConvert.toColor(circleConfig.getString(MapModule.PROPERTY_OVERLAY_COLOR), currentActivity);

PolygonOptions options = new PolygonOptions()
.fillColor(overlayColor)
.addAll(createOuterBounds())
.addHole(createHole(center, radius))
.strokeColor(strokeColor)
.strokeWidth(strokeWidth);

map.addPolygon(options);
}

/**
* Circle
*/
Expand Down
25 changes: 25 additions & 0 deletions android/src/ti/map/ViewProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class ViewProxy extends TiViewProxy implements AnnotationDelegate
private static final int MSG_ADD_CIRCLE = MSG_FIRST_ID + 921;
private static final int MSG_REMOVE_CIRCLE = MSG_FIRST_ID + 922;
private static final int MSG_REMOVE_ALL_CIRCLES = MSG_FIRST_ID + 923;
private static final int MSG_ADD_CUTOUT_CIRCLE = MSG_FIRST_ID + 924;

private static final int MSG_ADD_IMAGE_OVERLAY = MSG_FIRST_ID + 931;
private static final int MSG_REMOVE_IMAGE_OVERLAY = MSG_FIRST_ID + 932;
Expand Down Expand Up @@ -289,6 +290,13 @@ public boolean handleMessage(Message msg)
return true;
}

case MSG_ADD_CUTOUT_CIRCLE: {
result = (AsyncResult) msg.obj;
handleAddCutoutCircle((KrollDict) result.getArg());
result.setResult(null);
return true;
}

case MSG_REMOVE_CIRCLE: {
result = (AsyncResult) msg.obj;
handleRemoveCircle((CircleProxy) result.getArg());
Expand Down Expand Up @@ -1105,6 +1113,23 @@ public void handleAddCircle(CircleProxy circle)
}
}

@Kroll.method
public void addCutoutCircle(KrollDict circleConfiguration)
{
handleAddCutoutCircle(circleConfiguration);
}

public void handleAddCutoutCircle(KrollDict circleConfiguration)
{
TiUIView view = peekView();
if (view instanceof TiUIMapView) {
TiUIMapView mapView = (TiUIMapView) view;
if (mapView.getMap() != null) {
mapView.addCutoutCircle(circleConfiguration);
}
}
}

public void addPreloadCircle(CircleProxy c)
{
if (!preloadCircles.contains(c)) {
Expand Down
30 changes: 29 additions & 1 deletion apidoc/Map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -817,4 +817,32 @@ properties:
- <Modules.Map.SEARCH_RESULT_TYPE_ADDRESS>
- <Modules.Map.SEARCH_RESULT_TYPE_POINT_OF_INTEREST>
- <Modules.Map.SEARCH_RESULT_TYPE_QUERY>
type: Array<Number>
type: Array<Number>

---
name: CutoutCircleConfiguration
summary: Options to configure a cutout circle.
properties:
- name: longitude
summary: Longitude value of the map point, in decimal degrees.
type: Number
- name: latitude
summary: Latitude value of the map point, in decimal degrees.
type: Number
- name: radius
summary: The radius of the circle in meters.
type: Number
- name: overlayColor
summary: The color of the overlay (not the circle).
type: String
- name: strokeColor
summary: |
Color to use for the the polyline, as a color name or hex triplet.
description: |
For information about color values, see the "Colors" section of <Titanium.UI>.
type: String
default: black
- name: strokeWidth
summary: Line width in pixels to use when drawing the polyline.
type: Number
default: 10
17 changes: 17 additions & 0 deletions apidoc/View.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,23 @@ methods:
- name: removeAllPolylines
summary: Remove all polylines from the map.

- name: addCutoutCircle
summary: Adds a new cutout circle to the map.
description: |
A cutout circle represents a special polygon that spans over the
whole world and has a cutout in the shape of a circle. The radius
of the shape, the overlay color and stroke properties can be configured.
since: "12.4.0"
parameters:
- name: circleConfiguration
summary: A <CutoutCircleConfiguration> object.
type: CutoutCircleConfiguration

- name: removeCutoutCircle
summary: Removes a previously added cutout circle.
exclude-platforms: [android]
since: { iphone: "12.3.0", ipad: "12.3.0", macos: "12.3.0" }

- name: addCircle
summary: Adds a new circle to the map.
parameters:
Expand Down
12 changes: 12 additions & 0 deletions ios/Classes/TiCutoutCircle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Titanium SDK
* Copyright TiDev, Inc. 04/07/2022-Present. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/

#import <MapKit/MapKit.h>

@interface TiCutoutCircle : MKPolygon

@end
12 changes: 12 additions & 0 deletions ios/Classes/TiCutoutCircle.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Titanium SDK
* Copyright TiDev, Inc. 04/07/2022-Present. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/

#import "TiCutoutCircle.h"

@implementation TiCutoutCircle

@end
26 changes: 3 additions & 23 deletions ios/Classes/TiMapPolygonProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#import "TiMapPolygonProxy.h"
#import "TiMapUtils.h"

@implementation TiMapPolygonProxy

Expand Down Expand Up @@ -46,7 +47,7 @@ - (void)setupPolygon

for (int i = 0; i < [points count]; i++) {
id locObj = [points objectAtIndex:i];
CLLocationCoordinate2D coord = [self processLocation:locObj];
CLLocationCoordinate2D coord = [TiMapUtils processLocation:locObj];
coordArray[i] = coord;
}

Expand All @@ -61,7 +62,7 @@ - (void)setupPolygon

for (int j = 0; j < [holeObj count]; ++j) {
id obj = [holeObj objectAtIndex:j];
CLLocationCoordinate2D coord = [self processLocation:obj];
CLLocationCoordinate2D coord = [TiMapUtils processLocation:obj];
hole[j] = coord;
}

Expand All @@ -83,27 +84,6 @@ - (void)setupPolygon
[self applyStrokeWidth];
}

// A location can either be a an array of longitude, latitude pairings or
// an array of longitude, latitude objects.
// e.g. [ [123.33, 34.44], [100.39, 78.23], etc. ]
// [ {longitude: 123.33, latitude, 34.44}, {longitude: 100.39, latitude: 78.23}, etc. ]
- (CLLocationCoordinate2D)processLocation:(id)locObj
{
if ([locObj isKindOfClass:[NSDictionary class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectForKey:@"latitude"]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectForKey:@"longitude"]];

return CLLocationCoordinate2DMake(lat, lon);
} else if ([locObj isKindOfClass:[NSArray class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectAtIndex:1]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectAtIndex:0]];

return CLLocationCoordinate2DMake(lat, lon);
}

return kCLLocationCoordinate2DInvalid;
}

- (void)applyFillColor
{
if (polygonRenderer != nil) {
Expand Down
24 changes: 2 additions & 22 deletions ios/Classes/TiMapPolylineProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import "TiMapPolylineProxy.h"
#import "TiMapConstants.h"
#import "TiMapUtils.h"

@implementation TiMapPolylineProxy

Expand Down Expand Up @@ -45,7 +46,7 @@ - (void)setupPolyline

for (int i = 0; i < [points count]; i++) {
id locObj = [points objectAtIndex:i];
CLLocationCoordinate2D coord = [self processLocation:locObj];
CLLocationCoordinate2D coord = [TiMapUtils processLocation:locObj];
coordArray[i] = coord;
}

Expand All @@ -58,27 +59,6 @@ - (void)setupPolyline
[self applyStrokePattern];
}

// A location can either be a an array of longitude, latitude pairings or
// an array of longitude, latitude objects.
// e.g. [ [123.33, 34.44], [100.39, 78.23], etc. ]
// [ {longitude: 123.33, latitude, 34.44}, {longitude: 100.39, latitude: 78.23}, etc. ]
- (CLLocationCoordinate2D)processLocation:(id)locObj
{
if ([locObj isKindOfClass:[NSDictionary class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectForKey:@"latitude"]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectForKey:@"longitude"]];

return CLLocationCoordinate2DMake(lat, lon);
} else if ([locObj isKindOfClass:[NSArray class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectAtIndex:1]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectAtIndex:0]];

return CLLocationCoordinate2DMake(lat, lon);
}

return kCLLocationCoordinate2DInvalid;
}

- (void)applyStrokeColor
{
if (polylineRenderer != nil) {
Expand Down
4 changes: 4 additions & 0 deletions ios/Classes/TiMapUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@

+ (MKLocalSearchCompleterResultType)mappedResultTypes:(NSArray<NSNumber *> *)inputResultTypes;

+ (NSArray<NSDictionary *> *)generateCircleCoordinates:(CLLocationCoordinate2D)coordinate withRadius:(double)radius andTolerance:(double)tolerance;

+ (CLLocationCoordinate2D)processLocation:(id)locObj;

@end
43 changes: 43 additions & 0 deletions ios/Classes/TiMapUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,47 @@ + (MKLocalSearchCompleterResultType)mappedResultTypes:(NSArray<NSNumber *> *)inp
return resultTypes;
}

+ (NSArray<NSDictionary *> *)generateCircleCoordinates:(CLLocationCoordinate2D)coordinate withRadius:(double)radius andTolerance:(double)tolerance
{
NSMutableArray<NSDictionary *> *coordinates = [[NSMutableArray alloc] init];
double latRadian = coordinate.latitude * M_PI / 180.0;
double lngRadian = coordinate.longitude * M_PI / 180.0;
double distance = (radius / 1000.0) / 6371.0; // kms

for (double angle = 0; angle < 360.0; angle += tolerance) {
double bearing = angle * M_PI / 180.0;

double lat2 = asin(sin(latRadian) * cos(distance) + cos(latRadian) * sin(distance) * cos(bearing));
double lon2 = lngRadian + atan2(sin(bearing) * sin(distance) * cos(latRadian), cos(distance) - sin(latRadian) * sin(lat2));
lon2 = fmod(lon2 + 3 * M_PI, 2 * M_PI) - M_PI; // normalize to -180..+180º

NSNumber *latitude = @(lat2 * (180.0 / M_PI));
NSNumber *longitude = @(lon2 * (180.0 / M_PI));
[coordinates addObject:@{ @"latitude" : latitude, @"longitude" : longitude }];
}

return coordinates;
}

// A location can either be a an array of longitude, latitude pairings or
// an array of longitude, latitude objects.
// e.g. [ [123.33, 34.44], [100.39, 78.23], etc. ]
// [ {longitude: 123.33, latitude, 34.44}, {longitude: 100.39, latitude: 78.23}, etc. ]
+ (CLLocationCoordinate2D)processLocation:(id)locObj
{
if ([locObj isKindOfClass:[NSDictionary class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectForKey:@"latitude"]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectForKey:@"longitude"]];

return CLLocationCoordinate2DMake(lat, lon);
} else if ([locObj isKindOfClass:[NSArray class]]) {
CLLocationDegrees lat = [TiUtils doubleValue:[locObj objectAtIndex:1]];
CLLocationDegrees lon = [TiUtils doubleValue:[locObj objectAtIndex:0]];

return CLLocationCoordinate2DMake(lat, lon);
}

return kCLLocationCoordinate2DInvalid;
}

@end
Loading
Loading