Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Objective-C wrapper for proj-4, it doesn't do a lot, just forward and inverse projection for 2d coordinates. This code originated in Route-Me, but has been fixed so it actually works.
//
// RMProjection.h
//
// Copyright (c) 2008-2009, Route-Me Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/Foundation.h>
/*
If you want to trnasofrm between datums you need to include grid shift files in your bundle, and
set PROJ_LIB before you make any Projections
- (void)initUSProj {
NSString *conus = [[NSBundle mainBundle] pathForResource:@"conus" ofType:@""];
if(conus.length) {
NSString *path = [conus stringByDeletingLastPathComponent];
setenv("PROJ_LIB", [path cStringUsingEncoding:NSStringEncodingConversionAllowLossy], 1);
} else {
NSLog(@"Error, could not find proj dataum shifting file conus");
}
}
*/
/// Objective-C wrapper for PROJ4 map projection definitions.
@interface RMProjection : NSObject
// This is actually a PROJ4 projPJ, but it is typed as void* so the proj_api doesn't have to be included
@property (readwrite) void* internalProjection;
- (id) initWithString: (NSString*)params;
@end
//
// RMProjection.m
//
// Copyright (c) 2008-2009, Route-Me Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import "proj_api.h"
#import "RMProjection.h"
@implementation RMProjection
- (instancetype) initWithString: (NSString*)params {
self = [super init];
if (self) {
self.internalProjection = pj_init_plus([params UTF8String]);
if (self.internalProjection == NULL) {
NSLog(@"Unhandled error creating projection. String is %@", params);
return nil;
}
}
return self;
}
-(instancetype)init {
return [self initWithString:@"+proj=latlong +ellps=WGS84"];
}
-(void)dealloc {
if (_internalProjection)
pj_free(_internalProjection);
}
@end
//
// RMTransform.h
//
// Copyright (c) 2008-2009, Route-Me Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import <Foundation/Foundation.h>
@class RMProjection;
@interface RMTransform : NSObject
- (instancetype) initFrom: (RMProjection*)source To: (RMProjection*)dest;
-(CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point;
-(CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point;
@end
//
// RMTransform.m
//
// Copyright (c) 2008-2009, Route-Me Contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import "proj_api.h"
#import "RMTransform.h"
#import "RMProjection.h"
@interface RMTransform () {
RMProjection* source;
RMProjection* destination;
bool is_source_latlong;
bool is_dest_latlong;
}
@end
@implementation RMTransform
-(id) initFrom: (RMProjection*)_source To: (RMProjection*)_dest {
self = [super init];
if (self) {
source = _source;
destination = _dest;
if (source == nil || destination == nil) {
return nil;
}
is_source_latlong = pj_is_latlong(source.internalProjection);
is_dest_latlong = pj_is_latlong(destination.internalProjection);
}
return self;
}
- (CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point {
if (is_source_latlong) {
point.latitude *= DEG_TO_RAD;
point.longitude *= DEG_TO_RAD;
}
int retval = pj_transform(source.internalProjection, destination.internalProjection, 1, 0,
&point.longitude, &point.latitude, NULL);
if (is_dest_latlong) {
point.latitude *= RAD_TO_DEG;
point.longitude *= RAD_TO_DEG;
}
if (retval != 0) { // This should be fixed to handle these errors...
NSLog(@"Error occured during pj_transform: %s", pj_strerrno(retval));
}
return point;
}
- (CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point {
if (is_dest_latlong) {
point.latitude *= DEG_TO_RAD;
point.longitude *= DEG_TO_RAD;
}
int retval = pj_transform(destination.internalProjection, source.internalProjection, 1, 0,
&point.longitude,&point.latitude, NULL);
if (is_source_latlong) {
point.latitude *= RAD_TO_DEG;
point.longitude *= RAD_TO_DEG;
}
if (retval != 0) { // This should be fixed to handle these errors...
NSLog(@"Error occured during pj_transform: %s", pj_strerrno(retval));
}
return point;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.