How can I check if a CLLocationCoordinate2D is inside four CLLocationCoordinate2D Square? in Objective C with Google Maps

谁都会走 提交于 2019-12-04 07:29:30

If you have four points you can make a CGRect and use CGRectContainsPoint()

You just create a CLregion or CLCircularRegion and check if the coordinate is contained within the region...

Like this

CLCircularRegion *myRegion = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(22, -111) radius:500 identifier:@"myRegion"];
if ([myRegion containsCoordinate:CLLocationCoordinate2DMake(22.45, -111.1)]) {
    //Do what you want here
}

If the 4 points do not represent rectangle or a circle but any 4 points on the map you will need to create the system yourself. For a point to be inside a shape represented by 4 oriented points it is easiest to check the cross product between the center and each sequential pair of bounds points. All results must be positive for clock wise order for the point to be inside the bounds. The second thing is you need to convert the coordinates to cartesian system and orient them... Let the code speak for itself:

- (double)crossProductZCoordinateForCenter:(CLLocationCoordinate2D)center left:(CLLocationCoordinate2D)left right:(CLLocationCoordinate2D)right {
    CLLocationCoordinate2D A = CLLocationCoordinate2DMake(left.latitude-center.latitude, left.longitude-center.longitude);
    CLLocationCoordinate2D B = CLLocationCoordinate2DMake(right.latitude-center.latitude, right.longitude-center.longitude);

    return B.latitude*A.longitude - A.latitude*B.longitude;
}

- (BOOL)isCartesianCoordinate:(CLLocationCoordinate2D)coordinate insideBounds:(Bounds)bounds {
    // Now we will break the system into 4 triangles and check their orientation by using a z component of the cross product. If one of them if negative the coordinate is not inside the region
    if([self crossProductZCoordinateForCenter:coordinate left:bounds.southWest right:bounds.northWest] < .0) return NO;
    if([self crossProductZCoordinateForCenter:coordinate left:bounds.northWest right:bounds.northEast] < .0) return NO;
    if([self crossProductZCoordinateForCenter:coordinate left:bounds.northEast right:bounds.southEast] < .0) return NO;
    if([self crossProductZCoordinateForCenter:coordinate left:bounds.southEast right:bounds.southWest] < .0) return NO;
    return YES;
}

- (BOOL)isCoordinate:(CLLocationCoordinate2D)coordinate insideBounds:(Bounds)bounds {
    // We may treat the coordinates as cartesian but east should always be larger then west and north should be larger then south
    // Those smaller must be increased by 360 degrees
    if(bounds.southEast.latitude < bounds.southWest.latitude) bounds.southEast.latitude += 360.0;
    if(bounds.northEast.latitude < bounds.northWest.latitude) bounds.northEast.latitude += 360.0;
    if(bounds.northEast.longitude < bounds.southEast.longitude) bounds.northEast.longitude += 360.0;
    if(bounds.northWest.longitude < bounds.southWest.longitude) bounds.northWest.longitude += 360.0;
    // Check if any of the combination coordinates are cartesicly inside the bounds
    // We need to increase the longitude and the latitude by 360 and check all 4 combinations
    if([self isCartesianCoordinate:coordinate insideBounds:bounds]) return YES;
    if([self isCartesianCoordinate:CLLocationCoordinate2DMake(coordinate.latitude+360.0, coordinate.longitude) insideBounds:bounds]) return YES;
    if([self isCartesianCoordinate:CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude+360.0) insideBounds:bounds]) return YES;
    if([self isCartesianCoordinate:CLLocationCoordinate2DMake(coordinate.latitude+360.0, coordinate.longitude+360.0) insideBounds:bounds]) return YES;
    return NO;
}

And some simple tests might come in handy:

- (void)resampleCoordinate:(CLLocationCoordinate2D *)coordinate {
    if(coordinate->latitude < -180.0) coordinate->latitude += 360.0;
    if(coordinate->latitude > 180.0) coordinate->latitude -= 360.0;
    if(coordinate->longitude < -180.0) coordinate->longitude += 360.0;
    if(coordinate->longitude > 180.0) coordinate->longitude -= 360.0;
}

- (void)testLocationSystem {
    NSInteger numberOfTests = 0;
    NSInteger numberOfTestsCheckedOut = 0;

    for(double latitude = -180.0; latitude <= 180.0; latitude++) {
        for(double longitude = -180.0; longitude <= 180.0; longitude++) {
            Bounds bounds;
            bounds.southWest = CLLocationCoordinate2DMake(latitude-15.0, longitude-15.0);
            bounds.northEast = CLLocationCoordinate2DMake(latitude+15.0, longitude+15.0);
            bounds.northWest = CLLocationCoordinate2DMake(latitude-15.0, longitude+15.0);
            bounds.southEast = CLLocationCoordinate2DMake(latitude+15.0, longitude-15.0);
            [self resampleCoordinate:&(bounds.northWest)];
            [self resampleCoordinate:&(bounds.northEast)];
            [self resampleCoordinate:&(bounds.southEast)];
            [self resampleCoordinate:&(bounds.southWest)];

            numberOfTests++;
            BOOL success = [self isCoordinate:CLLocationCoordinate2DMake(latitude, longitude) insideBounds:bounds];
            if(success) {
                numberOfTestsCheckedOut++;
            }
            else {
                NSLog(@"Failed");
            }
        }
    }
    NSLog(@"%d/%d succeeded", (int)numberOfTestsCheckedOut, (int)numberOfTests);
}
- (void)testLocationFailSystem {
    NSInteger numberOfTests = 0;
    NSInteger numberOfTestsCheckedOut = 0;

    for(double latitude = -180.0; latitude <= 180.0; latitude++) {
        for(double longitude = -180.0; longitude <= 180.0; longitude++) {
            Bounds bounds;
            bounds.southWest = CLLocationCoordinate2DMake(latitude-15.0, longitude-15.0);
            bounds.northEast = CLLocationCoordinate2DMake(latitude+15.0, longitude+15.0);
            bounds.northWest = CLLocationCoordinate2DMake(latitude-15.0, longitude+15.0);
            bounds.southEast = CLLocationCoordinate2DMake(latitude+15.0, longitude-15.0);
            [self resampleCoordinate:&(bounds.northWest)];
            [self resampleCoordinate:&(bounds.northEast)];
            [self resampleCoordinate:&(bounds.southEast)];
            [self resampleCoordinate:&(bounds.southWest)];

            for(double angle = .0f; angle < M_PI; angle+=M_PI/10.0) {
                CLLocationCoordinate2D coordiunate = CLLocationCoordinate2DMake(latitude+cos(angle)*20.0, longitude+sin(angle)*20.0);
                [self resampleCoordinate:&coordiunate];

                numberOfTests++;

                BOOL success = [self isCoordinate:coordiunate insideBounds:bounds]; // must fail
                if(success == NO) {
                    numberOfTestsCheckedOut++;
                }
                else {
                    NSLog(@"Failed");
                }
            }

        }
    }
    NSLog(@"%d/%d succeeded", (int)numberOfTestsCheckedOut, (int)numberOfTests);
}

These all pass for me. If you find a situation not working but should or other way around please contact me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!