2011-05-31 16:27:34 -05:00
// TTTLocationFormatter . m
//
// Copyright ( c ) 2011 Mattt Thompson ( http : // mattt . me )
//
// Permission is hereby granted , free of charge , to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ) , to deal
// in the Software without restriction , including without limitation the rights
// to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
// copies of the Software , and to permit persons to whom the Software is
// furnished to do so , subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software .
//
// THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
// IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
// LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE .
# import "TTTLocationFormatter.h"
static double const kTTTMetersToKilometersCoefficient = 0.001 ;
static double const kTTTMetersToFeetCoefficient = 3.2808399 ;
static double const kTTTMetersToYardsCoefficient = 1.0936133 ;
static double const kTTTMetersToMilesCoefficient = 0.000621371192 ;
static inline double CLLocationDistanceToKilometers ( CLLocationDistance distance ) {
return distance * kTTTMetersToKilometersCoefficient ;
}
static inline double CLLocationDistanceToFeet ( CLLocationDistance distance ) {
return distance * kTTTMetersToFeetCoefficient ;
}
static inline double CLLocationDistanceToYards ( CLLocationDistance distance ) {
return distance * kTTTMetersToYardsCoefficient ;
}
static inline double CLLocationDistanceToMiles ( CLLocationDistance distance ) {
return distance * kTTTMetersToMilesCoefficient ;
}
# pragma mark -
static inline double DEG2RAD ( double degrees ) {
return degrees * M_PI / 180 ;
2011-09-22 12:04:23 -05:00
}
2011-05-31 16:27:34 -05:00
static inline double RAD2DEG ( double radians ) {
return radians * 180 / M_PI ;
2011-09-22 12:04:23 -05:00
}
2011-05-31 16:27:34 -05:00
static inline CLLocationDegrees CLLocationDegreesBearingBetweenCoordinates ( CLLocationCoordinate2D originCoordinate , CLLocationCoordinate2D destinationCoordinate ) {
double lat1 = DEG2RAD ( originCoordinate . latitude ) ;
double lon1 = DEG2RAD ( originCoordinate . longitude ) ;
double lat2 = DEG2RAD ( destinationCoordinate . latitude ) ;
double lon2 = DEG2RAD ( destinationCoordinate . longitude ) ;
double dLon = lon2 - lon1 ;
double y = sin ( dLon ) * cos ( lat2 ) ;
double x = cos ( lat1 ) * sin ( lat2 ) - sin ( lat1 ) * cos ( lat2 ) * cos ( dLon ) ;
double bearing = atan2 ( y , x ) + ( 2 * M_PI ) ;
// ` atan2` works on a range of - π to 0 to π , so add on 2 π and perform a modulo check
if ( bearing > ( 2 * M_PI ) ) {
bearing = bearing - ( 2 * M_PI ) ;
}
return RAD2DEG ( bearing ) ;
}
TTTLocationCardinalDirection TTTLocationCardinalDirectionFromBearing ( CLLocationDegrees bearing ) {
if ( bearing > 337.5 ) {
return TTTNorthDirection ;
} else if ( bearing > 292.5 ) {
return TTTNorthwestDirection ;
} else if ( bearing > 247.5 ) {
return TTTWestDirection ;
} else if ( bearing > 202.5 ) {
return TTTSouthwestDirection ;
} else if ( bearing > 157.5 ) {
return TTTSouthDirection ;
} else if ( bearing > 112.5 ) {
return TTTSoutheastDirection ;
} else if ( bearing > 67.5 ) {
return TTTEastDirection ;
} else if ( bearing > 22.5 ) {
return TTTNortheastDirection ;
} else {
return TTTNorthDirection ;
}
}
# pragma mark -
static double const kTTTMetersPerSecondToKilometersPerHourCoefficient = 3.6 ;
static double const kTTTMetersPerSecondToFeetPerSecondCoefficient = 3.2808399 ;
static double const kTTTMetersPerSecondToMilesPerHourCoefficient = 2.23693629 ;
static inline double CLLocationSpeedToKilometersPerHour ( CLLocationSpeed speed ) {
return speed * kTTTMetersPerSecondToKilometersPerHourCoefficient ;
}
static inline double CLLocationSpeedToFeetPerSecond ( CLLocationSpeed speed ) {
return speed * kTTTMetersPerSecondToFeetPerSecondCoefficient ;
}
static inline double CLLocationSpeedToMilesPerHour ( CLLocationSpeed speed ) {
return speed * kTTTMetersPerSecondToMilesPerHourCoefficient ;
}
@ interface TTTLocationFormatter ( )
@ property ( readwrite , nonatomic , assign ) TTTLocationFormatterCoordinateOrder coordinateOrder ;
@ property ( readwrite , nonatomic , assign ) TTTLocationFormatterBearingStyle bearingStyle ;
@ property ( readwrite , nonatomic , assign ) TTTLocationUnitSystem unitSystem ;
@ property ( readwrite , nonatomic , retain ) NSNumberFormatter * numberFormatter ;
@ end
@ implementation TTTLocationFormatter
@ synthesize coordinateOrder = _coordinateOrder ;
@ synthesize bearingStyle = _bearingStyle ;
@ synthesize unitSystem = _unitSystem ;
@ synthesize numberFormatter = _numberFormatter ;
- ( id ) init {
self = [ super init ] ;
if ( ! self ) {
return nil ;
}
self . coordinateOrder = TTTCoordinateLatLngOrder ;
self . bearingStyle = TTTBearingWordStyle ;
self . unitSystem = TTTMetricSystem ;
self . numberFormatter = [ [ [ NSNumberFormatter alloc ] init ] autorelease ] ;
[ self . numberFormatter setLocale : [ NSLocale currentLocale ] ] ;
[ self . numberFormatter setNumberStyle : NSNumberFormatterDecimalStyle ] ;
[ self . numberFormatter setMaximumSignificantDigits : 2 ] ;
[ self . numberFormatter setUsesSignificantDigits : YES ] ;
return self ;
}
- ( NSString * ) stringFromCoordinate : ( CLLocationCoordinate2D ) coordinate {
return [ NSString stringWithFormat : NSLocalizedString ( @ "(%@, %@)" , @ "Coordinate format" ) , [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : coordinate . latitude ] ] , [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : coordinate . longitude ] ] , nil ] ;
}
- ( NSString * ) stringFromLocation : ( CLLocation * ) location {
return [ self stringFromCoordinate : location . coordinate ] ;
}
- ( NSString * ) stringFromDistance : ( CLLocationDistance ) distance {
NSString * distanceString = nil ;
NSString * unitString = nil ;
switch ( self . unitSystem ) {
case TTTMetricSystem : {
2011-09-16 22:41:10 -05:00
double kilometerDistance = CLLocationDistanceToKilometers ( distance ) ;
2011-05-31 16:27:34 -05:00
if ( kilometerDistance > 1 ) {
distanceString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : kilometerDistance ] ] ;
unitString = NSLocalizedString ( @ "km" , @ "Kilometer Unit" ) ;
} else {
2011-09-16 22:41:10 -05:00
double meterDistance = distance ;
2011-05-31 16:27:34 -05:00
distanceString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : meterDistance ] ] ;
unitString = NSLocalizedString ( @ "m" , @ "Meter Unit" ) ;
}
break ;
}
case TTTImperialSystem : {
double feetDistance = CLLocationDistanceToFeet ( distance ) ;
if ( feetDistance < 300 ) {
distanceString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : feetDistance ] ] ;
unitString = NSLocalizedString ( @ "ft" , @ "Feet Unit" ) ;
} else {
2011-09-16 22:41:10 -05:00
double yardDistance = CLLocationDistanceToYards ( distance ) ;
if ( yardDistance < 500 ) {
distanceString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : yardDistance ] ] ;
unitString = NSLocalizedString ( @ "yds" , @ "Yard Unit" ) ;
} else {
double milesDistance = CLLocationDistanceToMiles ( distance ) ;
distanceString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : milesDistance ] ] ;
unitString = ( milesDistance > 1.0 && milesDistance < 1.1 ) ? NSLocalizedString ( @ "mile" , @ "Mile Unit (Singular)" ) : NSLocalizedString ( @ "miles" , @ "Mile Unit (Plural)" ) ;
}
2011-05-31 16:27:34 -05:00
}
break ;
}
}
return [ NSString stringWithFormat : NSLocalizedString ( @ "%@ %@" , @ "#{Distance} #{Unit}" ) , distanceString , unitString ] ;
}
- ( NSString * ) stringFromBearing : ( CLLocationDegrees ) bearing {
switch ( self . bearingStyle ) {
case TTTBearingWordStyle :
switch ( TTTLocationCardinalDirectionFromBearing ( bearing ) ) {
case TTTNorthDirection :
return NSLocalizedString ( @ "North" , @ "North Direction" ) ;
case TTTNortheastDirection :
return NSLocalizedString ( @ "Northeast" , @ "Northeast Direction" ) ;
case TTTEastDirection :
return NSLocalizedString ( @ "East" , @ "East Direction" ) ;
case TTTSoutheastDirection :
return NSLocalizedString ( @ "Southeast" , @ "Southeast Direction" ) ;
case TTTSouthDirection :
return NSLocalizedString ( @ "South" , @ "South Direction" ) ;
case TTTSouthwestDirection :
return NSLocalizedString ( @ "Southwest" , @ "Southwest Direction" ) ;
case TTTWestDirection :
return NSLocalizedString ( @ "West" , @ "West Direction" ) ;
case TTTNorthwestDirection :
return NSLocalizedString ( @ "Northwest" , @ "Northwest Direction" ) ;
}
break ;
case TTTBearingAbbreviationWordStyle :
switch ( TTTLocationCardinalDirectionFromBearing ( bearing ) ) {
case TTTNorthDirection :
return NSLocalizedString ( @ "N" , @ "North Direction Abbreviation" ) ;
case TTTNortheastDirection :
return NSLocalizedString ( @ "NE" , @ "Northeast Direction Abbreviation" ) ;
case TTTEastDirection :
return NSLocalizedString ( @ "E" , @ "East Direction Abbreviation" ) ;
case TTTSoutheastDirection :
return NSLocalizedString ( @ "SE" , @ "Southeast Direction Abbreviation" ) ;
case TTTSouthDirection :
return NSLocalizedString ( @ "S" , @ "South Direction Abbreviation" ) ;
case TTTSouthwestDirection :
return NSLocalizedString ( @ "SW" , @ "Southwest Direction Abbreviation" ) ;
case TTTWestDirection :
return NSLocalizedString ( @ "W" , @ "West Direction Abbreviation" ) ;
case TTTNorthwestDirection :
2011-09-26 11:06:56 -05:00
return NSLocalizedString ( @ "NW" , @ "Northwest Direction Abbreviation" ) ;
2011-05-31 16:27:34 -05:00
}
break ;
case TTTBearingNumericStyle :
return [ [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : bearing ] ] stringByAppendingString : NSLocalizedString ( @ "°" , @ "Degrees Symbol" ) ] ;
}
return nil ;
}
- ( NSString * ) stringFromSpeed : ( CLLocationSpeed ) speed {
NSString * speedString = nil ;
NSString * unitString = nil ;
switch ( self . unitSystem ) {
case TTTMetricSystem : {
double metersPerSecondSpeed = speed ;
double kilometersPerHourSpeed = CLLocationSpeedToKilometersPerHour ( speed ) ;
if ( kilometersPerHourSpeed > 1 ) {
speedString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : kilometersPerHourSpeed ] ] ;
unitString = NSLocalizedString ( @ "km/h" , @ "Kilometers Per Hour Unit" ) ;
} else {
speedString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : metersPerSecondSpeed ] ] ;
unitString = NSLocalizedString ( @ "m/s" , @ "Meters Per Second Unit" ) ;
}
break ;
}
case TTTImperialSystem : {
double feetPerSecondSpeed = CLLocationSpeedToFeetPerSecond ( speed ) ;
double milesPerHourSpeed = CLLocationSpeedToMilesPerHour ( speed ) ;
if ( milesPerHourSpeed > 1 ) {
speedString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : milesPerHourSpeed ] ] ;
unitString = NSLocalizedString ( @ "mph" , @ "Miles Per Hour Unit" ) ;
} else {
speedString = [ self . numberFormatter stringFromNumber : [ NSNumber numberWithDouble : feetPerSecondSpeed ] ] ;
unitString = NSLocalizedString ( @ "ft/s" , @ "Feet Per Second Unit" ) ;
}
break ;
}
}
return [ NSString stringWithFormat : NSLocalizedString ( @ "%@ %@" , @ "#{Speed} #{Unit}" ) , speedString , unitString ] ;
}
- ( NSString * ) stringFromDistanceFromLocation : ( CLLocation * ) originLocation toLocation : ( CLLocation * ) destinationLocation {
return [ self stringFromDistance : [ destinationLocation distanceFromLocation : originLocation ] ] ;
}
- ( NSString * ) stringFromBearingFromLocation : ( CLLocation * ) originLocation toLocation : ( CLLocation * ) destinationLocation {
return [ self stringFromBearing : CLLocationDegreesBearingBetweenCoordinates ( originLocation . coordinate , destinationLocation . coordinate ) ] ;
}
- ( NSString * ) stringFromDistanceAndBearingFromLocation : ( CLLocation * ) originLocation toLocation : ( CLLocation * ) destinationLocation {
return [ NSString stringWithFormat : NSLocalizedString ( @ "%@ %@" , @ "#{Dimensional Quantity} #{Direction}" ) , [ self stringFromDistanceFromLocation : originLocation toLocation : destinationLocation ] , [ self stringFromBearingFromLocation : originLocation toLocation : destinationLocation ] ] ;
}
- ( NSString * ) stringFromVelocityFromLocation : ( CLLocation * ) originLocation toLocation : ( CLLocation * ) destinationLocation atSpeed : ( CLLocationSpeed ) speed {
return [ NSString stringWithFormat : NSLocalizedString ( @ "%@ %@" , @ "#{Dimensional Quantity} #{Direction}" ) , [ self stringFromSpeed : speed ] , [ self stringFromBearingFromLocation : originLocation toLocation : destinationLocation ] ] ;
}
@ end