Closed Tyler-V closed 4 years ago
The function you are using has the signature:
CLLocationCoordinate2D CLLocationCoordinate2DMake(CLLocationDegrees latitude, CLLocationDegrees longitude);
You have passed the arguments:
CLLocationCoordinate2DMake(latLng.lng, latLng.lat);
Presumably, your .lng
maps to a longitude and .lat
maps to a latitude, which is the wrong order for the signature you're invoking.
@facetious good catch but unfortunately that's residual code leftover on trying to make it set the visible region properly.
CLLocationCoordinate2DMake(latLng.lng, latLng.lat) = Just south of Nigeria over the ocean. CLLocationCoordinate2DMake(latLng.lat, latLng.lng) = Further south west from Africa.
@Tyler-V see this blog post which pretty much covers the case with CLLocationCoordinate2DMake
GMSServices.provideAPIKey(APIKEY); console.log("Creating map view..."); camera = GMSCameraPosition.cameraWithLatitudeLongitudeZoom(-33.86, 151.20, 6); mapView = GMSMapView.mapWithFrameCamera(CGRectZero, camera); console.log("Setting a marker..."); marker = GMSMarker.alloc().init(); // Note that in-line functions such as CLLocationCoordinate2DMake are not exported. marker.position = { latitude: -33.86, longitude: 151.20 } marker.title ="Sydney"; marker.snippet ="Australia";
Hey @NickIliev thanks for the resource.
I don't think there is anything in that blog post that applies to my situation, sorry if my issue was unclear. I don't have any issues with creating a CLLocationCoordinate, that appears to be working just fine in other areas of my plugin.
The real issue at hand here is the marshalling of data and how to create the object that it is asking for.
I have an array of CLLocationCoordinates
.
The Mapbox SDK wants the following input parameter:
(Objective-C)
coordinates: interop.Pointer | interop.Reference<CLLocationCoordinate2D>, count: number
(Swift)
_ coordinates: UnsafePointer<CLLocationCoordinate2D>, count: UInt
As a workaround, I somehow cobbled together something that actually calls this API method:
const coordinates: CLLocationCoordinate2D[] = [];
for (let latLng of latLngs) {
const coordinate = CLLocationCoordinate2DMake(latLng.lng, latLng.lat);
coordinates.push(coordinate);
}
const array: any = NSArray.arrayWithArray([coordinates]);
mapView.setVisibleCoordinatesCountEdgePaddingDirectionDurationAnimationTimingFunctionCompletionHandler(
array,
coordinates.length,
insets,
0,
duration / 1000,
CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut),
() => {
resolve();
}
);
However, it sends my map to southwest Africa instead of where the latLngs are (US)... swapping the lat/lngs sends me further south from Africa over the ocean.
I cannot quickly test this, but I think that you should not wrap the JS array in another JS array. If you replace const array: any = NSArray.arrayWithArray([coordinates]);
with const array: any = NSArray.arrayWithArray(coordinates);
in the above snippet, I think it should work.
It seems I responded too fast. The above is not correct for multiple reasons:
NSArray
(see https://stackoverflow.com/a/4517970 if you're curious to know how it can be done)NSArray
but a nonnull const CLLocationCoordinate2D *
coordinates.The right way to construct an interop.Reference
to an array of CLLocationCoordinate2D (as well as any other C struct) is similar to the following:
function toCArrayOfLocations(a: CLLocationCoordinate2D[]): interop.Reference<CLLocationCoordinate2D> {
const ref = new interop.Reference<CLLocationCoordinate2D>(CLLocationCoordinate2D, interop.alloc(interop.sizeof(CLLocationCoordinate2D) * coordinates.length));
for (let i = 0; i < coordinates.length; i++) {
ref[i] = coordinates[i];
}
return ref;
}
const coordinates: CLLocationCoordinate2D[] = [CLLocationCoordinate2DMake(1, 2), CLLocationCoordinate2DMake(60, 190)];
const array = toCArrayOfLocations(coordinates);
Also, you can create a more generic helper function like this:
function toReferenceToCArray<T>(a: T[], type: interop.Type<T>): interop.Reference<T> {
const ref = new interop.Reference<T>(type, interop.alloc(interop.sizeof(type) * a.length));
for (let i = 0; i < a.length; i++) {
ref[i] = a[i];
}
return ref;
}
const coordinates: CLLocationCoordinate2D[] = [CLLocationCoordinate2DMake(1, 2), CLLocationCoordinate2DMake(60, 190)];
const refCoords = toReferenceToCArray(coordinates, CLLocationCoordinate2D);
@mbektchiev Thank you so much, that worked!
export function toReferenceToCArray<T>(input: T[], type: interop.Type<T>): interop.Reference<T> {
const ref = new interop.Reference<T>(type, interop.alloc(interop.sizeof(CLLocationCoordinate2D) * input.length));
for (let i = 0; i < input.length; i++) {
ref[i] = input[i];
}
return ref;
}
That indeed marshalls javascript arrays into interop.Reference<T>
thank you very much for the example, I couldn't find anything in the documentation this is great thanks again @mbektchiev
Oops, I noticed an error, if you intend to use this function with other types you should replace CLLocationCoordinate2D
with type
... 😆
Environment Provide version numbers for the following components (information can be retrieved by running
tns info
in your project folder or by inspecting thepackage.json
of the project):Describe the bug When attempting to call methods in the mapbox sdk, I am unable to marshall the data into the correct format shown in the examples depicted in Mapbox's documentation for iOS.
In this documentation provided:
I am unable to create an object of type
coordinates: interop.Pointer | interop.Reference<CLLocationCoordinate2D>
This calls the method without error, but what is passed in is an array of CLLocationCoordinate2D that is marshalled incorrectly. I know this because instead of the provided latLngs array taking me to a central part of the US which works on Android, it takes me off the coast of Africa.
To Reproduce Try to create a coordinates object of type interop.Pointer | interop.Reference, inspect the values created and coordinates are not correct.
Expected behavior I should be able to create an object of type interop.Pointer | interop.Reference where the value is properly mapped and doesn't result in an improper object.
Sample project I would be more than happy to invite you into my plugin's project which has a branch already setup and a demo-angular app which will let you bootstrap and debug this issue with minimal effort to see for yourself. Please let me know otherwise this should be easily reproducible given the steps listed above.