is there any way to get Google Maps zoom level calculate from lat/long delta values from the Google Maps SDK for iOS?
or maybe calculate it via Objective C ?
thanks
Perhaps this is what you are looking for.
From GMSCoordinateBounds.h:
/**
* Inits the northEast and southWest bounds corresponding
* to the rectangular region defined by the two corners.
*
* It is ambiguous whether the longitude of the box
* extends from |coord1| to |coord2| or vice-versa;
* the box is constructed as the smaller of the two variants, eliminating the
* ambiguity.
*/
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord1
coordinate:(CLLocationCoordinate2D)coord2;
It can be used to set the camera to fit the bounds with the appropriate zoom level.
CLLocationCoordinate2D coord1 = CLLocationCoordinate2DMake(-45.43563456, -23.32543646);
CLLocationCoordinate2D coord2 = CLLocationCoordinate2DMake(-21.32145323, -12.32455435);
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:coord1 coordinate:coord2];
[mapView moveCamera: [GMSCameraUpdate fitBounds:bounds]];
if somebody is searching it for swift, i also needed it for autocompletion, you can set bounds (example for south west germany near freiburg and stuttgart):
let coord1 : CLLocationCoordinate2D = CLLocationCoordinate2DMake(48.10009, 8.206787);
let coord2 : CLLocationCoordinate2D = CLLocationCoordinate2DMake(48.10009, 8.206787);
let bounds = GMSCoordinateBounds(coordinate: (coord1), coordinate: (coord2))
placesClient?.autocompleteQuery(autoQuery, bounds: bounds, filter: filter, callback: { (results, error: NSError?) -> Void in and so on.......
Related
I got a simd_float4*4 matrix from ARKit. I want to check the values of the matrix but found myself do not know how to do it in Objective-C. In Swift, this can be written as matrix.columns.3 to fetch a vector of values. But I do not know how to do it in Objective-C. Could someone point me a direction please. Thanks!
simd_float4x4 is a struct (like 4 simd_float4), and you can use
simd_float4x4.columns[index]
to access column in matrix.
/*! #abstract A matrix with 4 rows and 4 columns.*/
struct simd_float4x4 {
public var columns: (simd_float4, simd_float4, simd_float4, simd_float4)
public init()
public init(columns: (simd_float4, simd_float4, simd_float4, simd_float4))
}
Apple document link: https://developer.apple.com/documentation/simd/simd_float4x4?language=objc
hope helpful!
here's an example -- from this project, a pretty nice reference for Obj-C ARKit adventures -- https://github.com/markdaws/arkit-by-example/blob/part3/arkit-by-example/ViewController.m
- (void)insertGeometry:(ARHitTestResult *)hitResult {
// Right now we just insert a simple cube, later we will improve these to be more
// interesting and have better texture and shading
float dimension = 0.1;
SCNBox *cube = [SCNBox boxWithWidth:dimension height:dimension length:dimension chamferRadius:0];
SCNNode *node = [SCNNode nodeWithGeometry:cube];
// The physicsBody tells SceneKit this geometry should be manipulated by the physics engine
node.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:nil];
node.physicsBody.mass = 2.0;
node.physicsBody.categoryBitMask = CollisionCategoryCube;
// We insert the geometry slightly above the point the user tapped, so that it drops onto the plane
// using the physics engine
float insertionYOffset = 0.5;
node.position = SCNVector3Make(
hitResult.worldTransform.columns[3].x,
hitResult.worldTransform.columns[3].y + insertionYOffset,
hitResult.worldTransform.columns[3].z
);
[self.sceneView.scene.rootNode addChildNode:node];
[self.boxes addObject:node];
}
I am trying to find a simple method to determine whether a CLLocationCoordinate2D lies within the boundaries of an arbitrary shape defined by a series of other CLLocationCoordinate2D's. The shapes may be large enough that great-circle paths need to be considered.
CL used to have a circular region and the containsCoordinate: call to test against, but this has been deprecated in iOS7 and the dox do not contain a hint of what might replace it. I cannot find any other examples, notably one that works on polygons.
There are many similar questions here on SO, but they are not related to iOS specifically, and again, I can't seem to find one that works generally on great-circle polys.
Here's an example (using Algonquin Provincial Park) of an approach that may work for you.
To use CGPathContainsPoint for this purpose, an MKMapView is not required.
Nor is it necessary to create an MKPolygon or even to use the CLLocationCoordinate2D or MKMapPoint structs. They just make the code easier to understand.
The screenshot below was created from the data only for illustration purposes.
int numberOfCoordinates = 10;
//This example draws a crude polygon with 10 coordinates
//around Algonquin Provincial Park. Use as many coordinates
//as you like to achieve the accuracy you require.
CLLocationCoordinate2D algonquinParkCoordinates[numberOfCoordinates];
algonquinParkCoordinates[0] = CLLocationCoordinate2DMake(46.105, -79.4);
algonquinParkCoordinates[1] = CLLocationCoordinate2DMake(46.15487, -78.80759);
algonquinParkCoordinates[2] = CLLocationCoordinate2DMake(46.16629, -78.12095);
algonquinParkCoordinates[3] = CLLocationCoordinate2DMake(46.11964, -77.70896);
algonquinParkCoordinates[4] = CLLocationCoordinate2DMake(45.74140, -77.45627);
algonquinParkCoordinates[5] = CLLocationCoordinate2DMake(45.52630, -78.22532);
algonquinParkCoordinates[6] = CLLocationCoordinate2DMake(45.18662, -78.06601);
algonquinParkCoordinates[7] = CLLocationCoordinate2DMake(45.11689, -78.29123);
algonquinParkCoordinates[8] = CLLocationCoordinate2DMake(45.42230, -78.69773);
algonquinParkCoordinates[9] = CLLocationCoordinate2DMake(45.35672, -78.90647);
//Create CGPath from the above coordinates...
CGMutablePathRef mpr = CGPathCreateMutable();
for (int p=0; p < numberOfCoordinates; p++)
{
CLLocationCoordinate2D c = algonquinParkCoordinates[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, c.longitude, c.latitude);
else
CGPathAddLineToPoint(mpr, NULL, c.longitude, c.latitude);
}
//set up some test coordinates and test them...
int numberOfTests = 7;
CLLocationCoordinate2D testCoordinates[numberOfTests];
testCoordinates[0] = CLLocationCoordinate2DMake(45.5, -78.5);
testCoordinates[1] = CLLocationCoordinate2DMake(45.3, -79.1);
testCoordinates[2] = CLLocationCoordinate2DMake(45.1, -77.9);
testCoordinates[3] = CLLocationCoordinate2DMake(47.3, -79.6);
testCoordinates[4] = CLLocationCoordinate2DMake(45.5, -78.7);
testCoordinates[5] = CLLocationCoordinate2DMake(46.8, -78.4);
testCoordinates[6] = CLLocationCoordinate2DMake(46.1, -78.2);
for (int t=0; t < numberOfTests; t++)
{
CGPoint testCGPoint = CGPointMake(testCoordinates[t].longitude, testCoordinates[t].latitude);
BOOL tcInPolygon = CGPathContainsPoint(mpr, NULL, testCGPoint, FALSE);
NSLog(#"tc[%d] (%f,%f) in polygon = %#",
t,
testCoordinates[t].latitude,
testCoordinates[t].longitude,
(tcInPolygon ? #"Yes" : #"No"));
}
CGPathRelease(mpr);
Here are the results of the above test:
tc[0] (45.500000,-78.500000) in polygon = Yes
tc[1] (45.300000,-79.100000) in polygon = No
tc[2] (45.100000,-77.900000) in polygon = No
tc[3] (47.300000,-79.600000) in polygon = No
tc[4] (45.500000,-78.700000) in polygon = Yes
tc[5] (46.800000,-78.400000) in polygon = No
tc[6] (46.100000,-78.200000) in polygon = Yes
This screenshot is to illustrate the data only (actual MKMapView is not required to run the code above):
Anna's solution converted to Swift 3.0:
extension CLLocationCoordinate2D {
func contained(by vertices: [CLLocationCoordinate2D]) -> Bool {
let path = CGMutablePath()
for vertex in vertices {
if path.isEmpty {
path.move(to: CGPoint(x: vertex.longitude, y: vertex.latitude))
} else {
path.addLine(to: CGPoint(x: vertex.longitude, y: vertex.latitude))
}
}
let point = CGPoint(x: self.longitude, y: self.latitude)
return path.contains(point)
}
}
I am new to xcode, and am trying to create an annotation. The annotation works fine, its just that when the app opens the map is focused on europe! Should I change the coordinates to my latitude and longitude of my annotation location, and how do I do that? Beczuse there are four 0's instead of two! {{0,0},{0,0}} how do i configure latitude and longutude into that?
A MKCoordinateRegion has two fields: 1) center, 2) span.
You should use the MKCoordinateRegionMake macro for this:
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(35, -90); // pick desired values
MKCoordinateSpan span = MKCoordinateSpanMake(100, 100); // pick desired values
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
The syntax:
MKCoordinateRegion region = { { 0, 0 }, { 0, 0 } };
is a shortcut from C for initializing the struct values. The first pair is for the center field and the second pair is for the span field.
I have 2 coordinates, a top left and a bottom right. I would like to find the center point of the region. Right now I have the following method to calculate it. The center point is way off. When I call the method with
[self.map setRegionTopLeft: CLLocationCoordinate2DMake(21.57524, -157.984514)
bottomRight: CLLocationCoordinate2DMake(21.309766, -157.80766)
animated:YES];
It should center on the island of Oahu in the State of Hawaii, USA. I found this math here so I'm not sure whats going on.
Code A - This is way off. It's not putting me anywhere near the island.
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
CLLocationCoordinate2D centerPoint;
centerPoint.longitude = (topLeft.longitude + bottomRight.longitude) / 2;
if (fabs(bottomRight.longitude - topLeft.longitude) > 180)
{
if (centerPoint.longitude > 0)
{
centerPoint.longitude = centerPoint.longitude + 180;
} else {
centerPoint.longitude = centerPoint.longitude - 180;
}
}
centerPoint.latitude = asin((sin(bottomRight.latitude) + sin(topLeft.latitude))/2);
return centerPoint;
}
I've also, originally, tried this method. Its just what popped in my head when I thought center of a rectangle. If gets me a lot closer to what the center should be - I can see the island - but its still off.
Code B - Original code I tried. This is much closer to what I expected but still off.
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
CLLocationCoordinate2D centerPoint;
centerPoint.latitude = ((topLeft.latitude + bottomRight.latitude) / 2);
centerPoint.longitude = ((topLeft.longitude + bottomRight.longitude) / 2);
return centerPoint;
}
So given a coordinate region (topLeft, bottomRight) how to I get the center coordinate? The idea is I should be able to give any 2 coordinates and get the center coordinate.
Update* Code B works. I had my topLeft and bottomRight wrong. Code A puts me very south and a little east of where it should.
You need the middle of L(longitude) and B(latitude). For B the problem is around the pole, but as you set it, you simply can't "put the cap on the pole", so, really no problems here.
Middle(B1,B2)=(B1+B2)/2.
But L is much worse. L can jump from -179 to -179. And another problem : the middle of (-179,+179) should be 180, and middle(-1,+1) should be 0. I.e., we should always choose middle along shorter way between opposite points, not around the whole Earth.
We should move the zero meridian so, that the difference between L1,L2 will be smaller, than 180, make normal middle of them and then return the zero meridian back.
Let L1
if L2-L1>180, let's choose L2 for the new zero meridian.
shift=L2
L2=L2-shift, L1=L1+360-shift. Now, notice, L1-L2<180!
LmShifted=(L1+L2)/2
Lm=LmShifted+shift.
If we'll take these formulas together, we'll have:
Lm=(L1-L2+360)/2+L2
if L2-L1<180, Lm=(L1+L2)/2
The problem is when L2-L1=180. In this case you have two opposite meridians, dividing the Earth in two, and for the role of the middle both "quarter" meridian, to the right and to the left, fit. It's up to you, what to choose.
I'm doing some core graphics, and I wonder how I may know if a line will have some parts of it visible on screen.
Let's take a line going from x-5, y3 to x2, y-7. If it's 1 pixel wide, nothing will be displayed onscreen. If it's 15 pixels wide, some parts of it will be displayed.
How may I check that ?
If you have lines only you can work with the function below. Otherwise I would recommend to go through the whole length of your line and create in a specific distance an square of the line width size and check if it is inside your view. An example: If you have a line from x0y0 to x7y0. You would go to x1y0 create a square of your draw line size (in this example 15) and see if this overlaps your screen. Next go to x2y0 and so on. The advantage is it will even work with bezier curves (a little wiki information how bezier work will be enough).
// EDIT: (made a little bezier check function, should work, but haven't tested) And I don't think its more performance efficient to check each line before drawing:
- (void)bezierWithStart:(CGPoint)start cp1:(CGPoint)cp1 cp2:(CGPoint)cp2 end:(CGPoint)end withWidth:(float)wid {
for (float i = 0.0; i<=1.0; i+=0.05) { // how many steps
CGPoint chk1 = CGPointMake(start.x+((cp1.x-start.x)*i), start.y+((cp1.y-start.y)*i));
CGPoint chk2 = CGPointMake(cp1.x+((cp2.x-cp1.x)*i), cp1.y+((cp2.y-cp1.y)*i));
CGPoint chk3 = CGPointMake(cp2.x+((end.x-cp2.x)*i), cp2.y+((end.y-cp2.y)*i));
CGPoint chk4 = CGPointMake(chk1.x+((chk2.x-chk1.x)*i), chk1.y+((chk2.y-chk1.y)*i));
CGPoint chk5 = CGPointMake(chk2.x+((chk3.x-chk2.x)*i), chk2.y+((chk3.y-chk2.y)*i));
CGPoint cPoint = CGPointMake(chk4.x+((chk5.x-chk4.x)*i), chk4.y+((chk5.y-chk4.y)*i));
CGRect drawLine = CGRectMake(cPoint.x-(wid/2), cPoint.y-(wid/2), wid, wid);
// check if rect is in view
}
}
// EDIT end
But now lets go to the simple line function:
- (void)testLine:(CGPoint)fp toSecond:(CGPoint)sp withWidth:(float)wid {
float xratio = sp.x - fp.x;
float yratio = sp.y - fp.y;
double a = sqrt(((wid*wid)*(xratio*xratio))/((yratio*yratio)+(xratio*xratio)));
a/=2; // because line width goes in both direction
double b = (yratio/xratio)*a;
if ((xratio<0.0 && yratio<0.0) || (xratio>0.0 && yratio>0.0))b*=-1;
CGPoint diffFrom1 = CGPointMake(fp.x+a, fp.y+b);
CGPoint diffTo1 = CGPointMake(sp.x+a, sp.y+b);
a*=-1;
b*=-1;
CGPoint diffFrom2 = CGPointMake(fp.x+a, fp.y+b);
CGPoint diffTo2 = CGPointMake(sp.x+a, sp.y+b);
}
you will get 4 points. 2 lines, one above and one below the original line, half the size of your draw width. The calculation behind is to get the draw direction and for that the difference to the original line. But for those who want to get into it, heres my pre calculation: