├── .gitignore ├── ObjectiveWMM.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── stephen.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── stephen.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── ObjectiveWMM ├── CCMagneticDeclination.h ├── CCMagneticDeclination.m ├── CCMagneticModel.h ├── CCMagneticModel.m ├── Info.plist ├── NSDate+DecimalYear.h ├── NSDate+DecimalYear.m ├── ObjectiveWMM.h ├── WMM.COF └── WMM │ ├── EGM9615.h │ ├── GeomagnetismHeader.h │ ├── GeomagnetismLibrary.c │ └── PUBLIC_DOMAIN ├── ObjectiveWMMTests ├── DeclinationTests.m └── Info.plist └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/* 19 | *.xcuserdatad 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## SJT - do we need this still, given above lines? 27 | # *.xcuserstate 28 | 29 | ## Cocoapods 30 | Pods 31 | 32 | ## Subversion 33 | .svn -------------------------------------------------------------------------------- /ObjectiveWMM.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DC37B8661B3375E70041F93C /* ObjectiveWMM.h in Headers */ = {isa = PBXBuildFile; fileRef = DC70A01A1A400ED50055DCDE /* ObjectiveWMM.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | DC709FCC1A3FDB2E0055DCDE /* CCMagneticDeclination.h in Headers */ = {isa = PBXBuildFile; fileRef = DC709FB11A3FDB2E0055DCDE /* CCMagneticDeclination.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | DC709FCD1A3FDB2E0055DCDE /* CCMagneticDeclination.m in Sources */ = {isa = PBXBuildFile; fileRef = DC709FB21A3FDB2E0055DCDE /* CCMagneticDeclination.m */; }; 13 | DC709FCE1A3FDB2E0055DCDE /* CCMagneticModel.h in Headers */ = {isa = PBXBuildFile; fileRef = DC709FB31A3FDB2E0055DCDE /* CCMagneticModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | DC709FCF1A3FDB2E0055DCDE /* CCMagneticModel.m in Sources */ = {isa = PBXBuildFile; fileRef = DC709FB41A3FDB2E0055DCDE /* CCMagneticModel.m */; }; 15 | DC709FD91A3FDB2F0055DCDE /* NSDate+DecimalYear.h in Headers */ = {isa = PBXBuildFile; fileRef = DC709FC01A3FDB2E0055DCDE /* NSDate+DecimalYear.h */; }; 16 | DC709FDA1A3FDB2F0055DCDE /* NSDate+DecimalYear.m in Sources */ = {isa = PBXBuildFile; fileRef = DC709FC11A3FDB2E0055DCDE /* NSDate+DecimalYear.m */; }; 17 | DC709FDD1A3FDB2F0055DCDE /* EGM9615.h in Headers */ = {isa = PBXBuildFile; fileRef = DC709FC51A3FDB2E0055DCDE /* EGM9615.h */; }; 18 | DC709FDE1A3FDB2F0055DCDE /* GeomagnetismHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = DC709FC61A3FDB2E0055DCDE /* GeomagnetismHeader.h */; }; 19 | DC709FDF1A3FDB2F0055DCDE /* GeomagnetismLibrary.c in Sources */ = {isa = PBXBuildFile; fileRef = DC709FC71A3FDB2E0055DCDE /* GeomagnetismLibrary.c */; }; 20 | DC709FE01A3FDB2F0055DCDE /* PUBLIC_DOMAIN in Resources */ = {isa = PBXBuildFile; fileRef = DC709FC81A3FDB2E0055DCDE /* PUBLIC_DOMAIN */; }; 21 | DC709FE41A3FDC440055DCDE /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC709FE31A3FDC440055DCDE /* CoreLocation.framework */; }; 22 | DC709FEB1A3FDDE30055DCDE /* DeclinationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC709FEA1A3FDDE30055DCDE /* DeclinationTests.m */; }; 23 | DC709FEF1A3FE4A00055DCDE /* WMM.COF in Resources */ = {isa = PBXBuildFile; fileRef = DC709FEE1A3FE4A00055DCDE /* WMM.COF */; }; 24 | DC71D8DD197E067F00C665CB /* ObjectiveWMM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC71D8D1197E067F00C665CB /* ObjectiveWMM.framework */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | DC71D8DE197E067F00C665CB /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = DC71D8C8197E067F00C665CB /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = DC71D8D0197E067F00C665CB; 33 | remoteInfo = meeus64; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | DC709FB11A3FDB2E0055DCDE /* CCMagneticDeclination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCMagneticDeclination.h; sourceTree = ""; }; 39 | DC709FB21A3FDB2E0055DCDE /* CCMagneticDeclination.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCMagneticDeclination.m; sourceTree = ""; }; 40 | DC709FB31A3FDB2E0055DCDE /* CCMagneticModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCMagneticModel.h; sourceTree = ""; }; 41 | DC709FB41A3FDB2E0055DCDE /* CCMagneticModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCMagneticModel.m; sourceTree = ""; }; 42 | DC709FC01A3FDB2E0055DCDE /* NSDate+DecimalYear.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+DecimalYear.h"; sourceTree = ""; }; 43 | DC709FC11A3FDB2E0055DCDE /* NSDate+DecimalYear.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+DecimalYear.m"; sourceTree = ""; }; 44 | DC709FC51A3FDB2E0055DCDE /* EGM9615.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGM9615.h; sourceTree = ""; }; 45 | DC709FC61A3FDB2E0055DCDE /* GeomagnetismHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeomagnetismHeader.h; sourceTree = ""; }; 46 | DC709FC71A3FDB2E0055DCDE /* GeomagnetismLibrary.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GeomagnetismLibrary.c; sourceTree = ""; }; 47 | DC709FC81A3FDB2E0055DCDE /* PUBLIC_DOMAIN */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PUBLIC_DOMAIN; sourceTree = ""; }; 48 | DC709FE31A3FDC440055DCDE /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 49 | DC709FE61A3FDD5E0055DCDE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ObjectiveWMMTests/Info.plist; sourceTree = SOURCE_ROOT; }; 50 | DC709FE81A3FDD690055DCDE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | DC709FEA1A3FDDE30055DCDE /* DeclinationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeclinationTests.m; path = ObjectiveWMMTests/DeclinationTests.m; sourceTree = SOURCE_ROOT; }; 52 | DC709FEE1A3FE4A00055DCDE /* WMM.COF */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WMM.COF; sourceTree = ""; }; 53 | DC70A01A1A400ED50055DCDE /* ObjectiveWMM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectiveWMM.h; sourceTree = ""; }; 54 | DC71D8D1197E067F00C665CB /* ObjectiveWMM.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjectiveWMM.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | DC71D8DC197E067F00C665CB /* ObjectiveWMMTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ObjectiveWMMTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | DC71D8CD197E067F00C665CB /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | DC709FE41A3FDC440055DCDE /* CoreLocation.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | DC71D8D9197E067F00C665CB /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | DC71D8DD197E067F00C665CB /* ObjectiveWMM.framework in Frameworks */, 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | DC709FAE1A3FDB2E0055DCDE /* ObjectiveWMM */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | DC709FB11A3FDB2E0055DCDE /* CCMagneticDeclination.h */, 82 | DC709FB21A3FDB2E0055DCDE /* CCMagneticDeclination.m */, 83 | DC709FB31A3FDB2E0055DCDE /* CCMagneticModel.h */, 84 | DC709FB41A3FDB2E0055DCDE /* CCMagneticModel.m */, 85 | DC709FC01A3FDB2E0055DCDE /* NSDate+DecimalYear.h */, 86 | DC709FC11A3FDB2E0055DCDE /* NSDate+DecimalYear.m */, 87 | DC70A01A1A400ED50055DCDE /* ObjectiveWMM.h */, 88 | DC709FE51A3FDC840055DCDE /* Frameworks */, 89 | DC709FE21A3FDB9E0055DCDE /* Supporting Files */, 90 | DC709FC41A3FDB2E0055DCDE /* WMM */, 91 | DC709FEE1A3FE4A00055DCDE /* WMM.COF */, 92 | ); 93 | path = ObjectiveWMM; 94 | sourceTree = ""; 95 | }; 96 | DC709FC41A3FDB2E0055DCDE /* WMM */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | DC709FC51A3FDB2E0055DCDE /* EGM9615.h */, 100 | DC709FC61A3FDB2E0055DCDE /* GeomagnetismHeader.h */, 101 | DC709FC71A3FDB2E0055DCDE /* GeomagnetismLibrary.c */, 102 | DC709FC81A3FDB2E0055DCDE /* PUBLIC_DOMAIN */, 103 | ); 104 | path = WMM; 105 | sourceTree = ""; 106 | }; 107 | DC709FE21A3FDB9E0055DCDE /* Supporting Files */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | DC709FE81A3FDD690055DCDE /* Info.plist */, 111 | ); 112 | name = "Supporting Files"; 113 | sourceTree = ""; 114 | }; 115 | DC709FE51A3FDC840055DCDE /* Frameworks */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | DC709FE31A3FDC440055DCDE /* CoreLocation.framework */, 119 | ); 120 | name = Frameworks; 121 | sourceTree = ""; 122 | }; 123 | DC71D8C7197E067F00C665CB = { 124 | isa = PBXGroup; 125 | children = ( 126 | DC709FAE1A3FDB2E0055DCDE /* ObjectiveWMM */, 127 | DC71D8E0197E067F00C665CB /* ObjectiveWMMTests */, 128 | DC71D8D2197E067F00C665CB /* Products */, 129 | ); 130 | sourceTree = ""; 131 | }; 132 | DC71D8D2197E067F00C665CB /* Products */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | DC71D8D1197E067F00C665CB /* ObjectiveWMM.framework */, 136 | DC71D8DC197E067F00C665CB /* ObjectiveWMMTests.xctest */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | DC71D8E0197E067F00C665CB /* ObjectiveWMMTests */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | DC71D8E1197E067F00C665CB /* Supporting Files */, 145 | DC709FEA1A3FDDE30055DCDE /* DeclinationTests.m */, 146 | ); 147 | name = ObjectiveWMMTests; 148 | path = meeus64Tests; 149 | sourceTree = ""; 150 | }; 151 | DC71D8E1197E067F00C665CB /* Supporting Files */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | DC709FE61A3FDD5E0055DCDE /* Info.plist */, 155 | ); 156 | name = "Supporting Files"; 157 | sourceTree = ""; 158 | }; 159 | /* End PBXGroup section */ 160 | 161 | /* Begin PBXHeadersBuildPhase section */ 162 | DC71D8CE197E067F00C665CB /* Headers */ = { 163 | isa = PBXHeadersBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | DC37B8661B3375E70041F93C /* ObjectiveWMM.h in Headers */, 167 | DC709FCC1A3FDB2E0055DCDE /* CCMagneticDeclination.h in Headers */, 168 | DC709FCE1A3FDB2E0055DCDE /* CCMagneticModel.h in Headers */, 169 | DC709FDE1A3FDB2F0055DCDE /* GeomagnetismHeader.h in Headers */, 170 | DC709FDD1A3FDB2F0055DCDE /* EGM9615.h in Headers */, 171 | DC709FD91A3FDB2F0055DCDE /* NSDate+DecimalYear.h in Headers */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXHeadersBuildPhase section */ 176 | 177 | /* Begin PBXNativeTarget section */ 178 | DC71D8D0197E067F00C665CB /* ObjectiveWMM */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = DC71D8E7197E067F00C665CB /* Build configuration list for PBXNativeTarget "ObjectiveWMM" */; 181 | buildPhases = ( 182 | DC71D8CC197E067F00C665CB /* Sources */, 183 | DC71D8CD197E067F00C665CB /* Frameworks */, 184 | DC71D8CE197E067F00C665CB /* Headers */, 185 | DC71D8CF197E067F00C665CB /* Resources */, 186 | ); 187 | buildRules = ( 188 | ); 189 | dependencies = ( 190 | ); 191 | name = ObjectiveWMM; 192 | productName = meeus64; 193 | productReference = DC71D8D1197E067F00C665CB /* ObjectiveWMM.framework */; 194 | productType = "com.apple.product-type.framework"; 195 | }; 196 | DC71D8DB197E067F00C665CB /* ObjectiveWMMTests */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = DC71D8EA197E067F00C665CB /* Build configuration list for PBXNativeTarget "ObjectiveWMMTests" */; 199 | buildPhases = ( 200 | DC71D8D8197E067F00C665CB /* Sources */, 201 | DC71D8D9197E067F00C665CB /* Frameworks */, 202 | DC71D8DA197E067F00C665CB /* Resources */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | DC71D8DF197E067F00C665CB /* PBXTargetDependency */, 208 | ); 209 | name = ObjectiveWMMTests; 210 | productName = meeus64Tests; 211 | productReference = DC71D8DC197E067F00C665CB /* ObjectiveWMMTests.xctest */; 212 | productType = "com.apple.product-type.bundle.unit-test"; 213 | }; 214 | /* End PBXNativeTarget section */ 215 | 216 | /* Begin PBXProject section */ 217 | DC71D8C8197E067F00C665CB /* Project object */ = { 218 | isa = PBXProject; 219 | attributes = { 220 | BuildIndependentTargetsInParallel = YES; 221 | LastUpgradeCheck = 1520; 222 | ORGANIZATIONNAME = "Crookneck Consulting LLC"; 223 | TargetAttributes = { 224 | DC71D8D0197E067F00C665CB = { 225 | CreatedOnToolsVersion = 6.0; 226 | DevelopmentTeam = RMH7P6Q49N; 227 | }; 228 | DC71D8DB197E067F00C665CB = { 229 | CreatedOnToolsVersion = 6.0; 230 | DevelopmentTeam = RMH7P6Q49N; 231 | }; 232 | }; 233 | }; 234 | buildConfigurationList = DC71D8CB197E067F00C665CB /* Build configuration list for PBXProject "ObjectiveWMM" */; 235 | compatibilityVersion = "Xcode 3.2"; 236 | developmentRegion = en; 237 | hasScannedForEncodings = 0; 238 | knownRegions = ( 239 | en, 240 | Base, 241 | ); 242 | mainGroup = DC71D8C7197E067F00C665CB; 243 | productRefGroup = DC71D8D2197E067F00C665CB /* Products */; 244 | projectDirPath = ""; 245 | projectRoot = ""; 246 | targets = ( 247 | DC71D8D0197E067F00C665CB /* ObjectiveWMM */, 248 | DC71D8DB197E067F00C665CB /* ObjectiveWMMTests */, 249 | ); 250 | }; 251 | /* End PBXProject section */ 252 | 253 | /* Begin PBXResourcesBuildPhase section */ 254 | DC71D8CF197E067F00C665CB /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | DC709FEF1A3FE4A00055DCDE /* WMM.COF in Resources */, 259 | DC709FE01A3FDB2F0055DCDE /* PUBLIC_DOMAIN in Resources */, 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | DC71D8DA197E067F00C665CB /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXResourcesBuildPhase section */ 271 | 272 | /* Begin PBXSourcesBuildPhase section */ 273 | DC71D8CC197E067F00C665CB /* Sources */ = { 274 | isa = PBXSourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | DC709FDF1A3FDB2F0055DCDE /* GeomagnetismLibrary.c in Sources */, 278 | DC709FCD1A3FDB2E0055DCDE /* CCMagneticDeclination.m in Sources */, 279 | DC709FDA1A3FDB2F0055DCDE /* NSDate+DecimalYear.m in Sources */, 280 | DC709FCF1A3FDB2E0055DCDE /* CCMagneticModel.m in Sources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | DC71D8D8197E067F00C665CB /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | DC709FEB1A3FDDE30055DCDE /* DeclinationTests.m in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | /* End PBXSourcesBuildPhase section */ 293 | 294 | /* Begin PBXTargetDependency section */ 295 | DC71D8DF197E067F00C665CB /* PBXTargetDependency */ = { 296 | isa = PBXTargetDependency; 297 | target = DC71D8D0197E067F00C665CB /* ObjectiveWMM */; 298 | targetProxy = DC71D8DE197E067F00C665CB /* PBXContainerItemProxy */; 299 | }; 300 | /* End PBXTargetDependency section */ 301 | 302 | /* Begin XCBuildConfiguration section */ 303 | DC2C9C9D26DC26C4000D7A1F /* Distribution */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 308 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 309 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 310 | CLANG_CXX_LIBRARY = "libc++"; 311 | CLANG_ENABLE_MODULES = YES; 312 | CLANG_ENABLE_OBJC_ARC = YES; 313 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 314 | CLANG_WARN_BOOL_CONVERSION = YES; 315 | CLANG_WARN_COMMA = YES; 316 | CLANG_WARN_CONSTANT_CONVERSION = YES; 317 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INFINITE_RECURSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 325 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 326 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 327 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 328 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 329 | CLANG_WARN_STRICT_PROTOTYPES = YES; 330 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 334 | COPY_PHASE_STRIP = YES; 335 | CURRENT_PROJECT_VERSION = 1; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 339 | GCC_C_LANGUAGE_STANDARD = gnu99; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 342 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 348 | METAL_ENABLE_DEBUG_INFO = NO; 349 | SDKROOT = iphoneos; 350 | TARGETED_DEVICE_FAMILY = "1,2"; 351 | VALIDATE_PRODUCT = YES; 352 | VERSIONING_SYSTEM = "apple-generic"; 353 | VERSION_INFO_PREFIX = ""; 354 | }; 355 | name = Distribution; 356 | }; 357 | DC2C9C9E26DC26C4000D7A1F /* Distribution */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | CODE_SIGN_IDENTITY = ""; 361 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 362 | DEFINES_MODULE = YES; 363 | DYLIB_COMPATIBILITY_VERSION = 1; 364 | DYLIB_CURRENT_VERSION = 1; 365 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 366 | ENABLE_MODULE_VERIFIER = YES; 367 | FRAMEWORK_SEARCH_PATHS = ""; 368 | INFOPLIST_FILE = "$(SRCROOT)/ObjectiveWMM/Info.plist"; 369 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 370 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 371 | LD_RUNPATH_SEARCH_PATHS = ( 372 | "$(inherited)", 373 | "@executable_path/Frameworks", 374 | "@loader_path/Frameworks", 375 | ); 376 | MACH_O_TYPE = mh_dylib; 377 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; 378 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 379 | ONLY_ACTIVE_ARCH = NO; 380 | OTHER_LDFLAGS = "-ObjC"; 381 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.$(PRODUCT_NAME:rfc1034identifier)"; 382 | PRODUCT_NAME = ObjectiveWMM; 383 | PROVISIONING_PROFILE = ""; 384 | SKIP_INSTALL = YES; 385 | SUPPORTS_MACCATALYST = NO; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Distribution; 389 | }; 390 | DC2C9C9F26DC26C4000D7A1F /* Distribution */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | DEVELOPMENT_TEAM = RMH7P6Q49N; 394 | FRAMEWORK_SEARCH_PATHS = ( 395 | "$(SDKROOT)/Developer/Library/Frameworks", 396 | "$(inherited)", 397 | ); 398 | INFOPLIST_FILE = ObjectiveWMMTests/Info.plist; 399 | LD_RUNPATH_SEARCH_PATHS = ( 400 | "$(inherited)", 401 | "@executable_path/Frameworks", 402 | "@loader_path/Frameworks", 403 | ); 404 | METAL_ENABLE_DEBUG_INFO = NO; 405 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.${PRODUCT_NAME:rfc1034identifier}"; 406 | PRODUCT_NAME = ObjectiveWMMTests; 407 | }; 408 | name = Distribution; 409 | }; 410 | DC71D8E5197E067F00C665CB /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 415 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 417 | CLANG_CXX_LIBRARY = "libc++"; 418 | CLANG_ENABLE_MODULES = YES; 419 | CLANG_ENABLE_OBJC_ARC = YES; 420 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 421 | CLANG_WARN_BOOL_CONVERSION = YES; 422 | CLANG_WARN_COMMA = YES; 423 | CLANG_WARN_CONSTANT_CONVERSION = YES; 424 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 425 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INFINITE_RECURSION = YES; 429 | CLANG_WARN_INT_CONVERSION = YES; 430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 432 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 433 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 434 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 436 | CLANG_WARN_STRICT_PROTOTYPES = YES; 437 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 438 | CLANG_WARN_UNREACHABLE_CODE = YES; 439 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 440 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 441 | COPY_PHASE_STRIP = NO; 442 | CURRENT_PROJECT_VERSION = 1; 443 | ENABLE_STRICT_OBJC_MSGSEND = YES; 444 | ENABLE_TESTABILITY = YES; 445 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 446 | GCC_C_LANGUAGE_STANDARD = gnu99; 447 | GCC_DYNAMIC_NO_PIC = NO; 448 | GCC_NO_COMMON_BLOCKS = YES; 449 | GCC_OPTIMIZATION_LEVEL = 0; 450 | GCC_PREPROCESSOR_DEFINITIONS = ( 451 | "DEBUG=1", 452 | "$(inherited)", 453 | ); 454 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 455 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 456 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 457 | GCC_WARN_UNDECLARED_SELECTOR = YES; 458 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 459 | GCC_WARN_UNUSED_FUNCTION = YES; 460 | GCC_WARN_UNUSED_VARIABLE = YES; 461 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 462 | METAL_ENABLE_DEBUG_INFO = YES; 463 | ONLY_ACTIVE_ARCH = YES; 464 | SDKROOT = iphoneos; 465 | TARGETED_DEVICE_FAMILY = "1,2"; 466 | VERSIONING_SYSTEM = "apple-generic"; 467 | VERSION_INFO_PREFIX = ""; 468 | }; 469 | name = Debug; 470 | }; 471 | DC71D8E6197E067F00C665CB /* Release */ = { 472 | isa = XCBuildConfiguration; 473 | buildSettings = { 474 | ALWAYS_SEARCH_USER_PATHS = NO; 475 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 476 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 477 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 478 | CLANG_CXX_LIBRARY = "libc++"; 479 | CLANG_ENABLE_MODULES = YES; 480 | CLANG_ENABLE_OBJC_ARC = YES; 481 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 482 | CLANG_WARN_BOOL_CONVERSION = YES; 483 | CLANG_WARN_COMMA = YES; 484 | CLANG_WARN_CONSTANT_CONVERSION = YES; 485 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 486 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 487 | CLANG_WARN_EMPTY_BODY = YES; 488 | CLANG_WARN_ENUM_CONVERSION = YES; 489 | CLANG_WARN_INFINITE_RECURSION = YES; 490 | CLANG_WARN_INT_CONVERSION = YES; 491 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 492 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 493 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 494 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 495 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 496 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 497 | CLANG_WARN_STRICT_PROTOTYPES = YES; 498 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 499 | CLANG_WARN_UNREACHABLE_CODE = YES; 500 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 501 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 502 | COPY_PHASE_STRIP = YES; 503 | CURRENT_PROJECT_VERSION = 1; 504 | ENABLE_NS_ASSERTIONS = NO; 505 | ENABLE_STRICT_OBJC_MSGSEND = YES; 506 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 507 | GCC_C_LANGUAGE_STANDARD = gnu99; 508 | GCC_NO_COMMON_BLOCKS = YES; 509 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 510 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 511 | GCC_WARN_UNDECLARED_SELECTOR = YES; 512 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 513 | GCC_WARN_UNUSED_FUNCTION = YES; 514 | GCC_WARN_UNUSED_VARIABLE = YES; 515 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 516 | METAL_ENABLE_DEBUG_INFO = NO; 517 | SDKROOT = iphoneos; 518 | TARGETED_DEVICE_FAMILY = "1,2"; 519 | VALIDATE_PRODUCT = YES; 520 | VERSIONING_SYSTEM = "apple-generic"; 521 | VERSION_INFO_PREFIX = ""; 522 | }; 523 | name = Release; 524 | }; 525 | DC71D8E8197E067F00C665CB /* Debug */ = { 526 | isa = XCBuildConfiguration; 527 | buildSettings = { 528 | CODE_SIGN_IDENTITY = ""; 529 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 530 | DEBUG_INFORMATION_FORMAT = dwarf; 531 | DEFINES_MODULE = YES; 532 | DYLIB_COMPATIBILITY_VERSION = 1; 533 | DYLIB_CURRENT_VERSION = 1; 534 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 535 | ENABLE_MODULE_VERIFIER = YES; 536 | FRAMEWORK_SEARCH_PATHS = ""; 537 | INFOPLIST_FILE = "$(SRCROOT)/ObjectiveWMM/Info.plist"; 538 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 539 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 540 | LD_RUNPATH_SEARCH_PATHS = ( 541 | "$(inherited)", 542 | "@executable_path/Frameworks", 543 | "@loader_path/Frameworks", 544 | ); 545 | MACH_O_TYPE = mh_dylib; 546 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; 547 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 548 | ONLY_ACTIVE_ARCH = NO; 549 | OTHER_LDFLAGS = "-ObjC"; 550 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.$(PRODUCT_NAME:rfc1034identifier)"; 551 | PRODUCT_NAME = ObjectiveWMM; 552 | PROVISIONING_PROFILE = ""; 553 | SKIP_INSTALL = YES; 554 | SUPPORTS_MACCATALYST = NO; 555 | TARGETED_DEVICE_FAMILY = "1,2"; 556 | }; 557 | name = Debug; 558 | }; 559 | DC71D8E9197E067F00C665CB /* Release */ = { 560 | isa = XCBuildConfiguration; 561 | buildSettings = { 562 | CODE_SIGN_IDENTITY = ""; 563 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 564 | DEFINES_MODULE = YES; 565 | DYLIB_COMPATIBILITY_VERSION = 1; 566 | DYLIB_CURRENT_VERSION = 1; 567 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 568 | ENABLE_MODULE_VERIFIER = YES; 569 | FRAMEWORK_SEARCH_PATHS = ""; 570 | INFOPLIST_FILE = "$(SRCROOT)/ObjectiveWMM/Info.plist"; 571 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 572 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 573 | LD_RUNPATH_SEARCH_PATHS = ( 574 | "$(inherited)", 575 | "@executable_path/Frameworks", 576 | "@loader_path/Frameworks", 577 | ); 578 | MACH_O_TYPE = mh_dylib; 579 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; 580 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 581 | ONLY_ACTIVE_ARCH = NO; 582 | OTHER_LDFLAGS = "-ObjC"; 583 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.$(PRODUCT_NAME:rfc1034identifier)"; 584 | PRODUCT_NAME = ObjectiveWMM; 585 | PROVISIONING_PROFILE = ""; 586 | SKIP_INSTALL = YES; 587 | SUPPORTS_MACCATALYST = NO; 588 | TARGETED_DEVICE_FAMILY = "1,2"; 589 | }; 590 | name = Release; 591 | }; 592 | DC71D8EB197E067F00C665CB /* Debug */ = { 593 | isa = XCBuildConfiguration; 594 | buildSettings = { 595 | DEVELOPMENT_TEAM = RMH7P6Q49N; 596 | FRAMEWORK_SEARCH_PATHS = ( 597 | "$(SDKROOT)/Developer/Library/Frameworks", 598 | "$(inherited)", 599 | ); 600 | GCC_PREPROCESSOR_DEFINITIONS = ( 601 | "DEBUG=1", 602 | "$(inherited)", 603 | ); 604 | INFOPLIST_FILE = ObjectiveWMMTests/Info.plist; 605 | LD_RUNPATH_SEARCH_PATHS = ( 606 | "$(inherited)", 607 | "@executable_path/Frameworks", 608 | "@loader_path/Frameworks", 609 | ); 610 | METAL_ENABLE_DEBUG_INFO = YES; 611 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.${PRODUCT_NAME:rfc1034identifier}"; 612 | PRODUCT_NAME = ObjectiveWMMTests; 613 | }; 614 | name = Debug; 615 | }; 616 | DC71D8EC197E067F00C665CB /* Release */ = { 617 | isa = XCBuildConfiguration; 618 | buildSettings = { 619 | DEVELOPMENT_TEAM = RMH7P6Q49N; 620 | FRAMEWORK_SEARCH_PATHS = ( 621 | "$(SDKROOT)/Developer/Library/Frameworks", 622 | "$(inherited)", 623 | ); 624 | INFOPLIST_FILE = ObjectiveWMMTests/Info.plist; 625 | LD_RUNPATH_SEARCH_PATHS = ( 626 | "$(inherited)", 627 | "@executable_path/Frameworks", 628 | "@loader_path/Frameworks", 629 | ); 630 | METAL_ENABLE_DEBUG_INFO = NO; 631 | PRODUCT_BUNDLE_IDENTIFIER = "com.crookneckconsulting.${PRODUCT_NAME:rfc1034identifier}"; 632 | PRODUCT_NAME = ObjectiveWMMTests; 633 | }; 634 | name = Release; 635 | }; 636 | /* End XCBuildConfiguration section */ 637 | 638 | /* Begin XCConfigurationList section */ 639 | DC71D8CB197E067F00C665CB /* Build configuration list for PBXProject "ObjectiveWMM" */ = { 640 | isa = XCConfigurationList; 641 | buildConfigurations = ( 642 | DC71D8E5197E067F00C665CB /* Debug */, 643 | DC71D8E6197E067F00C665CB /* Release */, 644 | DC2C9C9D26DC26C4000D7A1F /* Distribution */, 645 | ); 646 | defaultConfigurationIsVisible = 0; 647 | defaultConfigurationName = Release; 648 | }; 649 | DC71D8E7197E067F00C665CB /* Build configuration list for PBXNativeTarget "ObjectiveWMM" */ = { 650 | isa = XCConfigurationList; 651 | buildConfigurations = ( 652 | DC71D8E8197E067F00C665CB /* Debug */, 653 | DC71D8E9197E067F00C665CB /* Release */, 654 | DC2C9C9E26DC26C4000D7A1F /* Distribution */, 655 | ); 656 | defaultConfigurationIsVisible = 0; 657 | defaultConfigurationName = Release; 658 | }; 659 | DC71D8EA197E067F00C665CB /* Build configuration list for PBXNativeTarget "ObjectiveWMMTests" */ = { 660 | isa = XCConfigurationList; 661 | buildConfigurations = ( 662 | DC71D8EB197E067F00C665CB /* Debug */, 663 | DC71D8EC197E067F00C665CB /* Release */, 664 | DC2C9C9F26DC26C4000D7A1F /* Distribution */, 665 | ); 666 | defaultConfigurationIsVisible = 0; 667 | defaultConfigurationName = Release; 668 | }; 669 | /* End XCConfigurationList section */ 670 | }; 671 | rootObject = DC71D8C8197E067F00C665CB /* Project object */; 672 | } 673 | -------------------------------------------------------------------------------- /ObjectiveWMM.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ObjectiveWMM.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ObjectiveWMM.xcodeproj/project.xcworkspace/xcuserdata/stephen.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ObjectiveWMM.xcodeproj/xcuserdata/stephen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ObjectiveWMM.xcscheme 8 | 9 | orderHint 10 | 4 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DC71D8D0197E067F00C665CB 16 | 17 | primary 18 | 19 | 20 | DC71D8DB197E067F00C665CB 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ObjectiveWMM/CCMagneticDeclination.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCMagneticDeclination.h 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface CCMagneticDeclination : NSObject 13 | 14 | - (id) initWithCoordinate:(CLLocationCoordinate2D)coordinate elevation:(CLLocationDistance)elevation date:(NSDate *)date magneticDeclination:(CLLocationDirection)magneticDeclination fieldStrength:(double)fieldStrength; 15 | 16 | @property (readonly, nonatomic) CLLocationCoordinate2D coordinate; 17 | @property (readonly, nonatomic) CLLocationDistance elevation; 18 | @property (readonly, nonatomic, strong) NSDate *date; 19 | @property (readonly, nonatomic) CLLocationDirection magneticDeclination; 20 | @property (readonly, nonatomic) double fieldStrength; // in μT 21 | 22 | - (CLLocationDirection) trueHeadingFromMagneticHeading:(CLLocationDirection)magneticHeading; 23 | - (CLLocationDirection) magneticHeadingFromTrueHeading:(CLLocationDirection)trueHeading; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ObjectiveWMM/CCMagneticDeclination.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCMagneticDeclination.m 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import "CCMagneticDeclination.h" 10 | 11 | static inline double withinZeroTo360(double degrees) { 12 | return (degrees - (360.0 * floor(degrees/360.0))); 13 | } 14 | 15 | @interface CCMagneticDeclination() 16 | 17 | @property (readwrite, nonatomic) CLLocationCoordinate2D coordinate; 18 | @property (readwrite, nonatomic) CLLocationDistance elevation; 19 | @property (readwrite, nonatomic, strong) NSDate *date; 20 | @property (readwrite, nonatomic) CLLocationDirection magneticDeclination; 21 | @property (readwrite, nonatomic) double fieldStrength; 22 | 23 | @end 24 | 25 | @implementation CCMagneticDeclination 26 | 27 | - (id) initWithCoordinate:(CLLocationCoordinate2D)coordinate elevation:(CLLocationDistance)elevation date:(NSDate *)date magneticDeclination:(CLLocationDirection)magneticDeclination fieldStrength:(double)fieldStrength { 28 | 29 | self = [super init]; 30 | if (self) { 31 | _coordinate = coordinate; 32 | _elevation = elevation; 33 | _date = date; 34 | _magneticDeclination = magneticDeclination; 35 | _fieldStrength = fieldStrength; 36 | } 37 | 38 | return self; 39 | } 40 | 41 | - (NSString *) description { 42 | 43 | NSString *desc = [NSString stringWithFormat:@"%1.3f°,%1.3f° / %1.2fm at %@: decl: %1.2f° F: %1.2fμT", self.coordinate.latitude, self.coordinate.longitude, self.elevation, self.date.description, self.magneticDeclination, self.fieldStrength]; 44 | 45 | return desc; 46 | } 47 | 48 | #pragma mark - NSCopying 49 | 50 | - (id)copyWithZone:(NSZone *)zone { 51 | 52 | CCMagneticDeclination *magneticDeclination = [[CCMagneticDeclination allocWithZone:zone] initWithCoordinate:self.coordinate elevation:self.elevation date:self.date magneticDeclination:self.magneticDeclination fieldStrength:self.fieldStrength]; 53 | 54 | return magneticDeclination; 55 | } 56 | 57 | #pragma mark - NSCoding 58 | 59 | - (id)initWithCoder:(NSCoder *)aDecoder { 60 | 61 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake([aDecoder decodeDoubleForKey:@"latitude"], [aDecoder decodeDoubleForKey:@"longitude"]); 62 | CLLocationDistance elevation = [aDecoder decodeDoubleForKey:@"elevation"]; 63 | NSDate *date = [aDecoder decodeObjectForKey:@"date"]; 64 | CLLocationDirection magneticDeclination = [aDecoder decodeDoubleForKey:@"magneticDeclination"]; 65 | double fieldStrength = [aDecoder decodeDoubleForKey:@"fieldStrength"]; 66 | 67 | self = [self initWithCoordinate:coord elevation:elevation date:date magneticDeclination:magneticDeclination fieldStrength:fieldStrength]; 68 | if (!self) { 69 | return nil; 70 | } 71 | 72 | return self; 73 | } 74 | 75 | - (void)encodeWithCoder:(NSCoder *)aCoder { 76 | 77 | [aCoder encodeDouble:self.coordinate.latitude forKey:@"latitude"]; 78 | [aCoder encodeDouble:self.coordinate.longitude forKey:@"longitude"]; 79 | [aCoder encodeDouble:self.elevation forKey:@"elevation"]; 80 | [aCoder encodeObject:self.date forKey:@"date"]; 81 | [aCoder encodeDouble:self.magneticDeclination forKey:@"magneticDeclination"]; 82 | [aCoder encodeDouble:self.fieldStrength forKey:@"fieldStrength"]; 83 | } 84 | 85 | #pragma mark - Public 86 | 87 | - (CLLocationDirection) trueHeadingFromMagneticHeading:(CLLocationDirection)magneticHeading { 88 | 89 | return withinZeroTo360(magneticHeading + self.magneticDeclination); 90 | } 91 | 92 | - (CLLocationDirection) magneticHeadingFromTrueHeading:(CLLocationDirection)trueHeading { 93 | 94 | return withinZeroTo360(trueHeading - self.magneticDeclination); 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /ObjectiveWMM/CCMagneticModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCMagneticDeclination.h 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import 13 | 14 | @interface CCMagneticModel : NSObject 15 | 16 | + (CCMagneticModel *) instance; 17 | 18 | +(CLLocationDirection) declinationForLocation:(CLLocation *) location; 19 | - (CCMagneticDeclination *) declinationForCoordinate:(CLLocationCoordinate2D)coordinate elevation:(CLLocationDistance)elevation date:(NSDate *)date; 20 | - (BOOL) dateIsWithinModelBounds:(NSDate *) date; 21 | - (NSDate *) modelValidityStart; 22 | - (NSDate *) modelValidityEnd; 23 | - (NSDate *) dateWithinModelBoundsFromDate:(NSDate *)date; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ObjectiveWMM/CCMagneticModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCMagneticDeclination.m 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | // 9 | // 10 | // Adapted from WMM Linux source code found here: http://www.ngdc.noaa.gov/geomag/WMM/soft.shtml 11 | // See wmm_point.c for sample of how to obtain geoMagneticElements for a given coordinate, elevation and date 12 | // This class implements exposes the same functionality through an Objective-C singleton class for iOS in order to obtain 13 | // the magnetic declination for an arbitrary coordinate. 14 | 15 | #import "CCMagneticModel.h" 16 | 17 | #import "GeomagnetismHeader.h" 18 | #import "EGM9615.h" 19 | 20 | #import "NSDate+DecimalYear.h" 21 | 22 | // courtesy of http://stackoverflow.com/questions/8650465/including-libraries-that-need-external-files-in-ios-project#comment10747339_8650503 23 | const char * getPathForResource(const char *fileName, const char *fileExtension) { 24 | 25 | NSString *fn = [NSString stringWithCString:fileName encoding:NSUTF8StringEncoding]; 26 | NSString *fe = [NSString stringWithCString:fileExtension encoding:NSUTF8StringEncoding]; 27 | 28 | NSString *path = [[NSBundle mainBundle] pathForResource:fn ofType:fe]; 29 | 30 | return [path cStringUsingEncoding:NSUTF8StringEncoding]; 31 | } 32 | 33 | @interface CCMagneticModel() 34 | 35 | - (BOOL) decimalYearIsWithinModelBounds:(NSDecimalNumber *)decimalYear; 36 | - (NSDate *) dateForYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day; 37 | 38 | @end 39 | 40 | @implementation CCMagneticModel { 41 | 42 | MAGtype_MagneticModel * _magneticModels[1], * _timedMagneticModel; 43 | MAGtype_Ellipsoid _ellip; 44 | MAGtype_Geoid _geoid; 45 | 46 | NSDecimalNumberHandler *_decimalHandler; 47 | } 48 | 49 | + (CCMagneticModel *) instance { 50 | static CCMagneticModel *_instance = nil; 51 | static dispatch_once_t onceToken; 52 | dispatch_once(&onceToken, ^{ 53 | _instance = [[CCMagneticModel alloc] init]; 54 | }); 55 | 56 | return _instance; 57 | } 58 | 59 | - (id) init { 60 | 61 | self = [super init]; 62 | if (self) { 63 | 64 | int epochs = 1; 65 | int numTerms, nMax = 0; 66 | 67 | NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.crookneckconsulting.ObjectiveWMM"]; 68 | NSString *path = [bundle pathForResource:@"WMM" ofType:@"COF"]; 69 | 70 | char *filename = (char *) [path cStringUsingEncoding:NSUTF8StringEncoding]; 71 | 72 | MAG_robustReadMagModels(filename, &_magneticModels, epochs); 73 | 74 | if (nMax < _magneticModels[0]->nMax) 75 | nMax = _magneticModels[0]->nMax; 76 | 77 | numTerms = ((nMax + 1) * (nMax + 2) / 2); 78 | 79 | _timedMagneticModel = MAG_AllocateModelMemory(numTerms); /* For storing the time modified WMM Model parameters */ 80 | 81 | if (_magneticModels[0] == NULL || _timedMagneticModel == NULL) { 82 | //MAG_Error(2); 83 | } 84 | 85 | MAG_SetDefaults(&_ellip, &_geoid); /* Set default values and constants */ 86 | 87 | /* Set EGM96 Geoid parameters */ 88 | _geoid.GeoidHeightBuffer = GeoidHeightBuffer; 89 | _geoid.Geoid_Initialized = 1; 90 | /* Set EGM96 Geoid parameters END */ 91 | 92 | // get a decimal number handler to allow us to round down decimal year values when testing dates in model bounds 93 | _decimalHandler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO]; 94 | } 95 | 96 | return self; 97 | } 98 | 99 | - (void) dealloc { 100 | 101 | MAG_FreeMagneticModelMemory(_timedMagneticModel); 102 | MAG_FreeMagneticModelMemory(_magneticModels[0]); 103 | } 104 | 105 | +(CLLocationDirection) declinationForLocation:(CLLocation *) location { 106 | CCMagneticModel *instance = [CCMagneticModel instance]; 107 | CCMagneticDeclination *declination = [instance declinationForCoordinate:location.coordinate elevation:location.altitude date:location.timestamp]; 108 | return declination.magneticDeclination; 109 | } 110 | 111 | - (CCMagneticDeclination *) declinationForCoordinate:(CLLocationCoordinate2D)coordinate elevation:(CLLocationDistance)elevation date:(NSDate *)date { 112 | 113 | MAGtype_CoordSpherical coordSpherical; 114 | MAGtype_Date userDate; 115 | 116 | MAGtype_CoordGeodetic coordGeodetic; 117 | MAGtype_GeoMagneticElements geoMagneticElements; 118 | 119 | // geodetic coordinates 120 | coordGeodetic.phi = coordinate.latitude; 121 | coordGeodetic.lambda = coordinate.longitude; 122 | coordGeodetic.HeightAboveEllipsoid = elevation/1000.0; // convert to km from metres 123 | coordGeodetic.HeightAboveGeoid = 0; 124 | coordGeodetic.UseGeoid = 0; 125 | 126 | // date of interest 127 | NSDecimalNumber *decimalYear = [date decimalYear]; 128 | userDate.DecimalYear = decimalYear.doubleValue; 129 | 130 | if (YES == [self decimalYearIsWithinModelBounds:decimalYear]) { 131 | // Convert from geodetic to Spherical Equations: 17-18, WMM Technical report 132 | MAG_GeodeticToSpherical(_ellip, coordGeodetic, &coordSpherical); 133 | 134 | // Time adjust the coefficients, Equation 19, WMM Technical report 135 | MAG_TimelyModifyMagneticModel(userDate, _magneticModels[0], _timedMagneticModel); 136 | 137 | // Computes the geoMagnetic field elements and their time change 138 | MAG_Geomag(_ellip, coordSpherical, coordGeodetic, _timedMagneticModel, &geoMagneticElements); 139 | 140 | MAG_CalculateGridVariation(coordGeodetic, &geoMagneticElements); 141 | 142 | CCMagneticDeclination *result = [[CCMagneticDeclination alloc] initWithCoordinate:coordinate elevation:elevation date:date magneticDeclination:geoMagneticElements.Decl fieldStrength:geoMagneticElements.F/1000.0]; 143 | 144 | return result; 145 | } 146 | 147 | // date was out of model bounds 148 | return nil; 149 | } 150 | 151 | - (BOOL) dateIsWithinModelBounds:(NSDate *) date { 152 | 153 | return [self decimalYearIsWithinModelBounds:[date decimalYear]]; 154 | } 155 | 156 | - (NSDate *) modelValidityStart { 157 | 158 | NSDate *validFrom = [self dateForYear: _magneticModels[0]->epoch month:1 day:1]; 159 | 160 | return validFrom; 161 | } 162 | 163 | - (NSDate *) modelValidityEnd { 164 | 165 | NSDate *validTo = [self dateForYear:_magneticModels[0]->CoefficientFileEndDate month:12 day:31]; 166 | 167 | return validTo; 168 | } 169 | 170 | - (NSDate *) dateWithinModelBoundsFromDate:(NSDate *)date { 171 | 172 | NSDate *modelStart = [self modelValidityStart]; 173 | if (date == [date earlierDate:modelStart]) 174 | return modelStart; 175 | 176 | // one second before model expiry, so that the floor of modelEnd.decimal year equals preceding year 177 | // (see decimalYearIsWithinModelBounds:) 178 | NSDate *modelEnd = [[self modelValidityEnd] dateByAddingTimeInterval:-1]; 179 | if (date == [date laterDate:modelEnd]) { 180 | return modelEnd; 181 | } 182 | 183 | return date; 184 | } 185 | 186 | #pragma mark - Private helper methods 187 | 188 | - (BOOL) decimalYearIsWithinModelBounds:(NSDecimalNumber *)decimalYear { 189 | 190 | double year = [decimalYear decimalNumberByRoundingAccordingToBehavior:_decimalHandler].doubleValue; 191 | if(year > _magneticModels[0]->CoefficientFileEndDate || year < _magneticModels[0]->epoch) { 192 | return NO; 193 | } 194 | 195 | return YES; 196 | } 197 | 198 | - (NSDate *) dateForYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { 199 | 200 | NSDateComponents *comps = [[NSDateComponents alloc] init]; 201 | [comps setDay:day]; 202 | [comps setMonth:month]; 203 | [comps setYear:year]; 204 | NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 205 | NSDate *date = [gregorian dateFromComponents:comps]; 206 | 207 | return date; 208 | } 209 | 210 | @end 211 | -------------------------------------------------------------------------------- /ObjectiveWMM/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ObjectiveWMM/NSDate+DecimalYear.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+DecimalYear.h 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDate (DecimalYear) 12 | 13 | - (NSDecimalNumber *) decimalYear; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ObjectiveWMM/NSDate+DecimalYear.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+DecimalYear.m 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 1/10/13. 6 | // Copyright (c) 2013 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import "NSDate+DecimalYear.h" 10 | 11 | @implementation NSDate (DecimalYear) 12 | 13 | - (NSDecimalNumber *) decimalYear { 14 | 15 | NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 16 | 17 | NSDateComponents *dateComponents = [gregorian components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour 18 | | NSCalendarUnitMinute | NSCalendarUnitSecond) fromDate:self]; 19 | 20 | NSDateComponents *startOfYearComponents = [[NSDateComponents alloc] init]; 21 | [startOfYearComponents setDay:1]; 22 | [startOfYearComponents setMonth:1]; 23 | [startOfYearComponents setYear:[dateComponents year]]; 24 | NSDate *startOfYear = [gregorian dateFromComponents:startOfYearComponents]; 25 | 26 | NSDateComponents *startOfNextYearComponents = [[NSDateComponents alloc] init]; 27 | [startOfNextYearComponents setDay:1]; 28 | [startOfNextYearComponents setMonth:1]; 29 | [startOfNextYearComponents setYear:[dateComponents year] + 1]; 30 | NSDate *startOfNextYear = [gregorian dateFromComponents:startOfNextYearComponents]; 31 | 32 | NSDecimalNumber *y = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithInteger:[dateComponents year]] decimalValue]]; 33 | NSDecimalNumber *d1 = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithFloat:[self timeIntervalSinceDate:startOfYear]] decimalValue]]; 34 | NSDecimalNumber *d2 = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithFloat:[startOfNextYear timeIntervalSinceDate:startOfYear]] decimalValue]]; 35 | 36 | NSDecimalNumber *result = [y decimalNumberByAdding:[d1 decimalNumberByDividingBy:d2]]; 37 | 38 | //double decimalYear = [dateComponents year] + (double) ([self timeIntervalSinceDate:startOfYear]/[startOfNextYear timeIntervalSinceDate:startOfYear]); 39 | 40 | return result; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ObjectiveWMM/ObjectiveWMM.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjectiveWMM.h 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 12/15/14. 6 | // Copyright (c) 2014 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ObjectiveWMM. 12 | FOUNDATION_EXPORT double ObjectiveWMMVersionNumber; 13 | 14 | //! Project version string for ObjectiveWMM. 15 | FOUNDATION_EXPORT const unsigned char ObjectiveWMMVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | #import 20 | #import -------------------------------------------------------------------------------- /ObjectiveWMM/WMM.COF: -------------------------------------------------------------------------------- 1 | 2025.0 WMM-2025 11/13/2024 2 | 1 0 -29351.8 0.0 12.0 0.0 3 | 1 1 -1410.8 4545.4 9.7 -21.5 4 | 2 0 -2556.6 0.0 -11.6 0.0 5 | 2 1 2951.1 -3133.6 -5.2 -27.7 6 | 2 2 1649.3 -815.1 -8.0 -12.1 7 | 3 0 1361.0 0.0 -1.3 0.0 8 | 3 1 -2404.1 -56.6 -4.2 4.0 9 | 3 2 1243.8 237.5 0.4 -0.3 10 | 3 3 453.6 -549.5 -15.6 -4.1 11 | 4 0 895.0 0.0 -1.6 0.0 12 | 4 1 799.5 278.6 -2.4 -1.1 13 | 4 2 55.7 -133.9 -6.0 4.1 14 | 4 3 -281.1 212.0 5.6 1.6 15 | 4 4 12.1 -375.6 -7.0 -4.4 16 | 5 0 -233.2 0.0 0.6 0.0 17 | 5 1 368.9 45.4 1.4 -0.5 18 | 5 2 187.2 220.2 0.0 2.2 19 | 5 3 -138.7 -122.9 0.6 0.4 20 | 5 4 -142.0 43.0 2.2 1.7 21 | 5 5 20.9 106.1 0.9 1.9 22 | 6 0 64.4 0.0 -0.2 0.0 23 | 6 1 63.8 -18.4 -0.4 0.3 24 | 6 2 76.9 16.8 0.9 -1.6 25 | 6 3 -115.7 48.8 1.2 -0.4 26 | 6 4 -40.9 -59.8 -0.9 0.9 27 | 6 5 14.9 10.9 0.3 0.7 28 | 6 6 -60.7 72.7 0.9 0.9 29 | 7 0 79.5 0.0 -0.0 0.0 30 | 7 1 -77.0 -48.9 -0.1 0.6 31 | 7 2 -8.8 -14.4 -0.1 0.5 32 | 7 3 59.3 -1.0 0.5 -0.8 33 | 7 4 15.8 23.4 -0.1 0.0 34 | 7 5 2.5 -7.4 -0.8 -1.0 35 | 7 6 -11.1 -25.1 -0.8 0.6 36 | 7 7 14.2 -2.3 0.8 -0.2 37 | 8 0 23.2 0.0 -0.1 0.0 38 | 8 1 10.8 7.1 0.2 -0.2 39 | 8 2 -17.5 -12.6 0.0 0.5 40 | 8 3 2.0 11.4 0.5 -0.4 41 | 8 4 -21.7 -9.7 -0.1 0.4 42 | 8 5 16.9 12.7 0.3 -0.5 43 | 8 6 15.0 0.7 0.2 -0.6 44 | 8 7 -16.8 -5.2 -0.0 0.3 45 | 8 8 0.9 3.9 0.2 0.2 46 | 9 0 4.6 0.0 -0.0 0.0 47 | 9 1 7.8 -24.8 -0.1 -0.3 48 | 9 2 3.0 12.2 0.1 0.3 49 | 9 3 -0.2 8.3 0.3 -0.3 50 | 9 4 -2.5 -3.3 -0.3 0.3 51 | 9 5 -13.1 -5.2 0.0 0.2 52 | 9 6 2.4 7.2 0.3 -0.1 53 | 9 7 8.6 -0.6 -0.1 -0.2 54 | 9 8 -8.7 0.8 0.1 0.4 55 | 9 9 -12.9 10.0 -0.1 0.1 56 | 10 0 -1.3 0.0 0.1 0.0 57 | 10 1 -6.4 3.3 0.0 0.0 58 | 10 2 0.2 0.0 0.1 -0.0 59 | 10 3 2.0 2.4 0.1 -0.2 60 | 10 4 -1.0 5.3 -0.0 0.1 61 | 10 5 -0.6 -9.1 -0.3 -0.1 62 | 10 6 -0.9 0.4 0.0 0.1 63 | 10 7 1.5 -4.2 -0.1 0.0 64 | 10 8 0.9 -3.8 -0.1 -0.1 65 | 10 9 -2.7 0.9 -0.0 0.2 66 | 10 10 -3.9 -9.1 -0.0 -0.0 67 | 11 0 2.9 0.0 0.0 0.0 68 | 11 1 -1.5 0.0 -0.0 -0.0 69 | 11 2 -2.5 2.9 0.0 0.1 70 | 11 3 2.4 -0.6 0.0 -0.0 71 | 11 4 -0.6 0.2 0.0 0.1 72 | 11 5 -0.1 0.5 -0.1 -0.0 73 | 11 6 -0.6 -0.3 0.0 -0.0 74 | 11 7 -0.1 -1.2 -0.0 0.1 75 | 11 8 1.1 -1.7 -0.1 -0.0 76 | 11 9 -1.0 -2.9 -0.1 0.0 77 | 11 10 -0.2 -1.8 -0.1 0.0 78 | 11 11 2.6 -2.3 -0.1 0.0 79 | 12 0 -2.0 0.0 0.0 0.0 80 | 12 1 -0.2 -1.3 0.0 -0.0 81 | 12 2 0.3 0.7 -0.0 0.0 82 | 12 3 1.2 1.0 -0.0 -0.1 83 | 12 4 -1.3 -1.4 -0.0 0.1 84 | 12 5 0.6 -0.0 -0.0 -0.0 85 | 12 6 0.6 0.6 0.1 -0.0 86 | 12 7 0.5 -0.1 -0.0 -0.0 87 | 12 8 -0.1 0.8 0.0 0.0 88 | 12 9 -0.4 0.1 0.0 -0.0 89 | 12 10 -0.2 -1.0 -0.1 -0.0 90 | 12 11 -1.3 0.1 -0.0 0.0 91 | 12 12 -0.7 0.2 -0.1 -0.1 92 | 999999999999999999999999999999999999999999999999 93 | 999999999999999999999999999999999999999999999999 94 | -------------------------------------------------------------------------------- /ObjectiveWMM/WMM/GeomagnetismHeader.h: -------------------------------------------------------------------------------- 1 | /* WMM Subroutine library was tested in the following environments 2 | * 3 | * 1. Red Hat Linux with GCC Compiler 4 | * 2. MS Windows XP with CodeGear C++ compiler 5 | * 3. Sun Solaris with GCC Compiler 6 | * 7 | * 8 | * Revision Number: $Revision: 1288 $ 9 | * Last changed by: $Author: awoods $ 10 | * Last changed on: $Date: 2014-12-09 16:43:07 -0700 (Tue, 09 Dec 2014) $ 11 | * 12 | * 13 | */ 14 | 15 | 16 | #ifndef _POSIX_C_SOURCE 17 | #define _POSIX_C_SOURCE 18 | #endif 19 | 20 | /* 21 | #ifndef EPOCHRANGE 22 | #define EPOCHRANGE (int)5 23 | #endif 24 | */ 25 | 26 | #ifndef GEOMAGHEADER_H 27 | #define GEOMAGHEADER_H 28 | 29 | #define READONLYMODE "r" 30 | #define MAXLINELENGTH (1024) 31 | #define NOOFPARAMS (15) 32 | #define NOOFCOEFFICIENTS (7) 33 | 34 | #define _DEGREE_NOT_FOUND (-2) 35 | #define CALCULATE_NUMTERMS(N) (N * ( N + 1 ) / 2 + N) 36 | 37 | /*These error values come from the ISCWSA error model: 38 | *http://www.copsegrove.com/Pages/MWDGeomagneticModels.aspx 39 | */ 40 | #define INCL_ERROR_BASE (0.20) 41 | #define DECL_ERROR_OFFSET_BASE (0.36) 42 | #define F_ERROR_BASE (130) 43 | #define DECL_ERROR_SLOPE_BASE (5000) 44 | #define WMM_ERROR_MULTIPLIER 1.21 45 | #define IGRF_ERROR_MULTIPLIER 1.21 46 | 47 | /*These error values are the NGDC error model 48 | * 49 | */ 50 | #define WMM_UNCERTAINTY_F 152 51 | #define WMM_UNCERTAINTY_H 133 52 | #define WMM_UNCERTAINTY_X 138 53 | #define WMM_UNCERTAINTY_Y 89 54 | #define WMM_UNCERTAINTY_Z 165 55 | #define WMM_UNCERTAINTY_I 0.22 56 | #define WMM_UNCERTAINTY_D_OFFSET 0.24 57 | #define WMM_UNCERTAINTY_D_COEF 5432 58 | 59 | 60 | #ifndef M_PI 61 | #define M_PI ((2)*(acos(0.0))) 62 | #endif 63 | 64 | #define RAD2DEG(rad) ((rad)*(180.0L/M_PI)) 65 | #define DEG2RAD(deg) ((deg)*(M_PI/180.0L)) 66 | #define ATanH(x) (0.5 * log((1 + x) / (1 - x))) 67 | 68 | #ifndef TRUE 69 | #define TRUE ((int)1) 70 | #endif 71 | #ifndef FALSE 72 | #define FALSE ((int)0) 73 | #endif 74 | 75 | 76 | 77 | #define MAG_PS_MIN_LAT_DEGREE -55 /* Minimum Latitude for Polar Stereographic projection in degrees */ 78 | #define MAG_PS_MAX_LAT_DEGREE 55 /* Maximum Latitude for Polar Stereographic projection in degrees */ 79 | #define MAG_UTM_MIN_LAT_DEGREE -80.5 /* Minimum Latitude for UTM projection in degrees */ 80 | #define MAG_UTM_MAX_LAT_DEGREE 84.5 /* Maximum Latitude for UTM projection in degrees */ 81 | 82 | #define MAG_GEO_POLE_TOLERANCE 1e-5 83 | #define MAG_USE_GEOID 1 /* 1 Geoid - Ellipsoid difference should be corrected, 0 otherwise */ 84 | 85 | /* 86 | Data types and prototype declaration for 87 | World Magnetic Model (WMM) subroutines. 88 | 89 | July 28, 2009 90 | 91 | manoj.c.nair@noaa.gov*/ 92 | 93 | 94 | typedef struct { 95 | double EditionDate; 96 | double epoch; /*Base time of Geomagnetic model epoch (yrs)*/ 97 | char ModelName[32]; 98 | double *Main_Field_Coeff_G; /* C - Gauss coefficients of main geomagnetic model (nT) Index is (n * (n + 1) / 2 + m) */ 99 | double *Main_Field_Coeff_H; /* C - Gauss coefficients of main geomagnetic model (nT) */ 100 | double *Secular_Var_Coeff_G; /* CD - Gauss coefficients of secular geomagnetic model (nT/yr) */ 101 | double *Secular_Var_Coeff_H; /* CD - Gauss coefficients of secular geomagnetic model (nT/yr) */ 102 | int nMax; /* Maximum degree of spherical harmonic model */ 103 | int nMaxSecVar; /* Maximum degree of spherical harmonic secular model */ 104 | int SecularVariationUsed; /* Whether or not the magnetic secular variation vector will be needed by program*/ 105 | double CoefficientFileEndDate; 106 | 107 | } MAGtype_MagneticModel; 108 | 109 | typedef struct { 110 | double a; /*semi-major axis of the ellipsoid*/ 111 | double b; /*semi-minor axis of the ellipsoid*/ 112 | double fla; /* flattening */ 113 | double epssq; /*first eccentricity squared */ 114 | double eps; /* first eccentricity */ 115 | double re; /* mean radius of ellipsoid*/ 116 | } MAGtype_Ellipsoid; 117 | 118 | typedef struct { 119 | double lambda; /* longitude */ 120 | double phi; /* geodetic latitude */ 121 | double HeightAboveEllipsoid; /* height above the ellipsoid (HaE) */ 122 | double HeightAboveGeoid; /* (height above the EGM96 geoid model ) */ 123 | int UseGeoid; 124 | } MAGtype_CoordGeodetic; 125 | 126 | typedef struct { 127 | double lambda; /* longitude*/ 128 | double phig; /* geocentric latitude*/ 129 | double r; /* distance from the center of the ellipsoid*/ 130 | } MAGtype_CoordSpherical; 131 | 132 | typedef struct { 133 | int Year; 134 | int Month; 135 | int Day; 136 | double DecimalYear; /* decimal years */ 137 | } MAGtype_Date; 138 | 139 | typedef struct { 140 | double *Pcup; /* Legendre Function */ 141 | double *dPcup; /* Derivative of Legendre fcn */ 142 | } MAGtype_LegendreFunction; 143 | 144 | typedef struct { 145 | double Bx; /* North */ 146 | double By; /* East */ 147 | double Bz; /* Down */ 148 | } MAGtype_MagneticResults; 149 | 150 | typedef struct { 151 | double *RelativeRadiusPower; /* [earth_reference_radius_km / sph. radius ]^n */ 152 | double *cos_mlambda; /*cp(m) - cosine of (m*spherical coord. longitude)*/ 153 | double *sin_mlambda; /* sp(m) - sine of (m*spherical coord. longitude) */ 154 | } MAGtype_SphericalHarmonicVariables; 155 | 156 | typedef struct { 157 | double Decl; /* 1. Angle between the magnetic field vector and true north, positive east*/ 158 | double Incl; /*2. Angle between the magnetic field vector and the horizontal plane, positive down*/ 159 | double F; /*3. Magnetic Field Strength*/ 160 | double H; /*4. Horizontal Magnetic Field Strength*/ 161 | double X; /*5. Northern component of the magnetic field vector*/ 162 | double Y; /*6. Eastern component of the magnetic field vector*/ 163 | double Z; /*7. Downward component of the magnetic field vector*/ 164 | double GV; /*8. The Grid Variation*/ 165 | double Decldot; /*9. Yearly Rate of change in declination*/ 166 | double Incldot; /*10. Yearly Rate of change in inclination*/ 167 | double Fdot; /*11. Yearly rate of change in Magnetic field strength*/ 168 | double Hdot; /*12. Yearly rate of change in horizontal field strength*/ 169 | double Xdot; /*13. Yearly rate of change in the northern component*/ 170 | double Ydot; /*14. Yearly rate of change in the eastern component*/ 171 | double Zdot; /*15. Yearly rate of change in the downward component*/ 172 | double GVdot; /*16. Yearly rate of change in grid variation*/ 173 | } MAGtype_GeoMagneticElements; 174 | 175 | typedef struct { 176 | int NumbGeoidCols; /* 360 degrees of longitude at 15 minute spacing */ 177 | int NumbGeoidRows; /* 180 degrees of latitude at 15 minute spacing */ 178 | int NumbHeaderItems; /* min, max lat, min, max long, lat, long spacing*/ 179 | int ScaleFactor; /* 4 grid cells per degree at 15 minute spacing */ 180 | float *GeoidHeightBuffer; 181 | int NumbGeoidElevs; 182 | int Geoid_Initialized; /* indicates successful initialization */ 183 | int UseGeoid; /*Is the Geoid being used?*/ 184 | } MAGtype_Geoid; 185 | 186 | typedef struct { 187 | int UseGradient; 188 | MAGtype_GeoMagneticElements GradPhi; /* phi */ 189 | MAGtype_GeoMagneticElements GradLambda; /* lambda */ 190 | MAGtype_GeoMagneticElements GradZ; 191 | } MAGtype_Gradient; 192 | 193 | typedef struct { 194 | char Longitude[40]; 195 | char Latitude[40]; 196 | } MAGtype_CoordGeodeticStr; 197 | 198 | typedef struct { 199 | double Easting; /* (X) in meters*/ 200 | double Northing; /* (Y) in meters */ 201 | int Zone; /*UTM Zone*/ 202 | char HemiSphere; 203 | double CentralMeridian; 204 | double ConvergenceOfMeridians; 205 | double PointScale; 206 | } MAGtype_UTMParameters; 207 | 208 | enum PARAMS { 209 | SHDF, 210 | MODELNAME, 211 | PUBLISHER, 212 | RELEASEDATE, 213 | DATACUTOFF, 214 | MODELSTARTYEAR, 215 | MODELENDYEAR, 216 | EPOCH, 217 | INTSTATICDEG, 218 | INTSECVARDEG, 219 | EXTSTATICDEG, 220 | EXTSECVARDEG, 221 | GEOMAGREFRAD, 222 | NORMALIZATION, 223 | SPATBASFUNC 224 | }; 225 | 226 | enum COEFFICIENTS { 227 | IE, 228 | N, 229 | M, 230 | GNM, 231 | HNM, 232 | DGNM, 233 | DHNM 234 | }; 235 | 236 | enum YYYYMMDD { 237 | YEAR, 238 | MONTH, 239 | DAY 240 | }; 241 | 242 | /*Prototypes */ 243 | 244 | /*Functions that should be Magnetic Model member functions*/ 245 | 246 | 247 | 248 | /*Wrapper Functions*/ 249 | int MAG_Geomag(MAGtype_Ellipsoid Ellip, 250 | MAGtype_CoordSpherical CoordSpherical, 251 | MAGtype_CoordGeodetic CoordGeodetic, 252 | MAGtype_MagneticModel *TimedMagneticModel, 253 | MAGtype_GeoMagneticElements *GeoMagneticElements); 254 | 255 | void MAG_Gradient(MAGtype_Ellipsoid Ellip, 256 | MAGtype_CoordGeodetic CoordGeodetic, 257 | MAGtype_MagneticModel *TimedMagneticModel, 258 | MAGtype_Gradient *Gradient); 259 | 260 | int MAG_Grid(MAGtype_CoordGeodetic minimum, 261 | MAGtype_CoordGeodetic maximum, 262 | double cord_step_size, 263 | double altitude_step_size, 264 | double time_step, 265 | MAGtype_MagneticModel *MagneticModel, 266 | MAGtype_Geoid *Geoid, 267 | MAGtype_Ellipsoid Ellip, 268 | MAGtype_Date StartDate, 269 | MAGtype_Date EndDate, 270 | int ElementOption, 271 | int UncertaintyOption, 272 | int PrintOption, 273 | char *OutputFile); 274 | 275 | 276 | int MAG_robustReadMagneticModel_Large(char *filename, char* filenameSV, MAGtype_MagneticModel **MagneticModel); 277 | 278 | int MAG_robustReadMagModels(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size); 279 | 280 | int MAG_SetDefaults(MAGtype_Ellipsoid *Ellip, MAGtype_Geoid *Geoid); 281 | 282 | /*User Interface*/ 283 | 284 | void MAG_Error(int control); 285 | 286 | char MAG_GeomagIntroduction_WMM(MAGtype_MagneticModel *MagneticModel, char *VersionDate); 287 | 288 | char MAG_GeomagIntroduction_EMM(MAGtype_MagneticModel *MagneticModel, char *VersionDate); 289 | 290 | int MAG_GetUserGrid(MAGtype_CoordGeodetic *minimum, 291 | MAGtype_CoordGeodetic *maximum, 292 | double *step_size, 293 | double *a_step_size, 294 | double *step_time, 295 | MAGtype_Date *StartDate, 296 | MAGtype_Date *EndDate, 297 | int *ElementOption, 298 | int *PrintOption, 299 | char *OutputFile, 300 | MAGtype_Geoid *Geoid); 301 | 302 | int MAG_GetUserInput(MAGtype_MagneticModel *MagneticModel, 303 | MAGtype_Geoid *Geoid, 304 | MAGtype_CoordGeodetic *CoordGeodetic, 305 | MAGtype_Date *MagneticDate); 306 | 307 | void MAG_PrintGradient(MAGtype_Gradient Gradient); 308 | 309 | void MAG_PrintUserData(MAGtype_GeoMagneticElements GeomagElements, 310 | MAGtype_CoordGeodetic SpaceInput, 311 | MAGtype_Date TimeInput, 312 | MAGtype_MagneticModel *MagneticModel, 313 | MAGtype_Geoid *Geoid); 314 | 315 | 316 | 317 | int MAG_ValidateDMSstringlat(char *input, char *Error); 318 | 319 | int MAG_ValidateDMSstringlong(char *input, char *Error); 320 | 321 | int MAG_Warnings(int control, double value, MAGtype_MagneticModel *MagneticModel); 322 | 323 | /*Memory and File Processing*/ 324 | 325 | MAGtype_LegendreFunction *MAG_AllocateLegendreFunctionMemory(int NumTerms); 326 | 327 | MAGtype_MagneticModel *MAG_AllocateModelMemory(int NumTerms); 328 | 329 | MAGtype_SphericalHarmonicVariables *MAG_AllocateSphVarMemory(int nMax); 330 | 331 | void MAG_AssignHeaderValues(MAGtype_MagneticModel *model, char values[][MAXLINELENGTH]); 332 | 333 | void MAG_AssignMagneticModelCoeffs(MAGtype_MagneticModel *Assignee, MAGtype_MagneticModel *Source, int nMax, int nMaxSecVar); 334 | 335 | int MAG_FreeMemory(MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_LegendreFunction *LegendreFunction); 336 | 337 | int MAG_FreeLegendreMemory(MAGtype_LegendreFunction *LegendreFunction); 338 | 339 | int MAG_FreeMagneticModelMemory(MAGtype_MagneticModel *MagneticModel); 340 | 341 | int MAG_FreeSphVarMemory(MAGtype_SphericalHarmonicVariables *SphVar); 342 | 343 | void MAG_PrintWMMFormat(char *filename, MAGtype_MagneticModel *MagneticModel); 344 | 345 | void MAG_PrintEMMFormat(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel); 346 | 347 | void MAG_PrintSHDFFormat(char *filename, MAGtype_MagneticModel *(*MagneticModel)[], int epochs); 348 | 349 | int MAG_readMagneticModel(char *filename, MAGtype_MagneticModel *MagneticModel); 350 | 351 | int MAG_readMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel); 352 | 353 | int MAG_readMagneticModel_SHDF(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size); 354 | 355 | char *MAG_Trim(char *str); 356 | 357 | /*Conversions, Transformations, and other Calculations*/ 358 | void MAG_BaseErrors(double DeclCoef, double DeclBaseline, double InclOffset, double FOffset, double Multiplier, double H, double* DeclErr, double* InclErr, double* FErr); 359 | 360 | int MAG_CalculateGeoMagneticElements(MAGtype_MagneticResults *MagneticResultsGeo, MAGtype_GeoMagneticElements *GeoMagneticElements); 361 | 362 | void MAG_CalculateGradientElements(MAGtype_MagneticResults GradResults, MAGtype_GeoMagneticElements MagneticElements, MAGtype_GeoMagneticElements *GradElements); 363 | 364 | int MAG_CalculateSecularVariationElements(MAGtype_MagneticResults MagneticVariation, MAGtype_GeoMagneticElements *MagneticElements); 365 | 366 | int MAG_CalculateGridVariation(MAGtype_CoordGeodetic location, MAGtype_GeoMagneticElements *elements); 367 | 368 | void MAG_CartesianToGeodetic(MAGtype_Ellipsoid Ellip, double x, double y, double z, MAGtype_CoordGeodetic *CoordGeodetic); 369 | 370 | MAGtype_CoordGeodetic MAG_CoordGeodeticAssign(MAGtype_CoordGeodetic CoordGeodetic); 371 | 372 | int MAG_DateToYear(MAGtype_Date *Calendar_Date, char *Error); 373 | 374 | void MAG_DegreeToDMSstring(double DegreesOfArc, int UnitDepth, char *DMSstring); 375 | 376 | void MAG_DMSstringToDegree(char *DMSstring, double *DegreesOfArc); 377 | 378 | void MAG_ErrorCalc(MAGtype_GeoMagneticElements B, MAGtype_GeoMagneticElements* Errors); 379 | 380 | int MAG_GeodeticToSpherical(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_CoordSpherical *CoordSpherical); 381 | 382 | MAGtype_GeoMagneticElements MAG_GeoMagneticElementsAssign(MAGtype_GeoMagneticElements Elements); 383 | 384 | MAGtype_GeoMagneticElements MAG_GeoMagneticElementsScale(MAGtype_GeoMagneticElements Elements, double factor); 385 | 386 | MAGtype_GeoMagneticElements MAG_GeoMagneticElementsSubtract(MAGtype_GeoMagneticElements minuend, MAGtype_GeoMagneticElements subtrahend); 387 | 388 | int MAG_GetTransverseMercator(MAGtype_CoordGeodetic CoordGeodetic, MAGtype_UTMParameters *UTMParameters); 389 | 390 | int MAG_GetUTMParameters(double Latitude, 391 | double Longitude, 392 | int *Zone, 393 | char *Hemisphere, 394 | double *CentralMeridian); 395 | 396 | int MAG_isNaN(double d); 397 | 398 | int MAG_RotateMagneticVector(MAGtype_CoordSpherical, 399 | MAGtype_CoordGeodetic CoordGeodetic, 400 | MAGtype_MagneticResults MagneticResultsSph, 401 | MAGtype_MagneticResults *MagneticResultsGeo); 402 | 403 | void MAG_SphericalToCartesian(MAGtype_CoordSpherical CoordSpherical, double *x, double *y, double *z); 404 | 405 | void MAG_SphericalToGeodetic(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic *CoordGeodetic); 406 | 407 | void MAG_TMfwd4(double Eps, double Epssq, double K0R4, double K0R4oa, 408 | double Acoeff[], double Lam0, double K0, double falseE, 409 | double falseN, int XYonly, double Lambda, double Phi, 410 | double *X, double *Y, double *pscale, double *CoM); 411 | 412 | int MAG_YearToDate(MAGtype_Date *Date); 413 | 414 | 415 | /*Spherical Harmonics*/ 416 | 417 | int MAG_AssociatedLegendreFunction(MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_LegendreFunction *LegendreFunction); 418 | 419 | int MAG_CheckGeographicPole(MAGtype_CoordGeodetic *CoordGeodetic); 420 | 421 | int MAG_ComputeSphericalHarmonicVariables(MAGtype_Ellipsoid Ellip, 422 | MAGtype_CoordSpherical CoordSpherical, 423 | int nMax, 424 | MAGtype_SphericalHarmonicVariables * SphVariables); 425 | 426 | void MAG_GradY(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, 427 | MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements GeoMagneticElements, MAGtype_GeoMagneticElements *GradYElements); 428 | 429 | void MAG_GradYSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *GradY); 430 | 431 | int MAG_PcupHigh(double *Pcup, double *dPcup, double x, int nMax); 432 | 433 | int MAG_PcupLow(double *Pcup, double *dPcup, double x, int nMax); 434 | 435 | int MAG_SecVarSummation(MAGtype_LegendreFunction *LegendreFunction, 436 | MAGtype_MagneticModel *MagneticModel, 437 | MAGtype_SphericalHarmonicVariables SphVariables, 438 | MAGtype_CoordSpherical CoordSpherical, 439 | MAGtype_MagneticResults *MagneticResults); 440 | 441 | int MAG_SecVarSummationSpecial(MAGtype_MagneticModel *MagneticModel, 442 | MAGtype_SphericalHarmonicVariables SphVariables, 443 | MAGtype_CoordSpherical CoordSpherical, 444 | MAGtype_MagneticResults *MagneticResults); 445 | 446 | int MAG_Summation(MAGtype_LegendreFunction *LegendreFunction, 447 | MAGtype_MagneticModel *MagneticModel, 448 | MAGtype_SphericalHarmonicVariables SphVariables, 449 | MAGtype_CoordSpherical CoordSpherical, 450 | MAGtype_MagneticResults *MagneticResults); 451 | 452 | int MAG_SummationSpecial(MAGtype_MagneticModel *MagneticModel, 453 | MAGtype_SphericalHarmonicVariables SphVariables, 454 | MAGtype_CoordSpherical CoordSpherical, 455 | MAGtype_MagneticResults *MagneticResults); 456 | 457 | int MAG_TimelyModifyMagneticModel(MAGtype_Date UserDate, MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel); 458 | 459 | /*Geoid*/ 460 | 461 | 462 | int MAG_ConvertGeoidToEllipsoidHeight(MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Geoid *Geoid); 463 | /* 464 | * The function Convert_Geoid_To_Ellipsoid_Height converts the specified WGS84 465 | * geoid height at the specified geodetic coordinates to the equivalent 466 | * ellipsoid height, using the EGM96 gravity model. 467 | * 468 | * Latitude : Geodetic latitude in radians (input) 469 | * Longitude : Geodetic longitude in radians (input) 470 | * Geoid_Height : Geoid height, in meters (input) 471 | * Ellipsoid_Height : Ellipsoid height, in meters. (output) 472 | * 473 | */ 474 | 475 | int MAG_GetGeoidHeight(double Latitude, double Longitude, double *DeltaHeight, MAGtype_Geoid *Geoid); 476 | /* 477 | * The private function Get_Geoid_Height returns the height of the 478 | * WGS84 geiod above or below the WGS84 ellipsoid, 479 | * at the specified geodetic coordinates, 480 | * using a grid of height adjustments from the EGM96 gravity model. 481 | * 482 | * Latitude : Geodetic latitude in radians (input) 483 | * Longitude : Geodetic longitude in radians (input) 484 | * DeltaHeight : Height Adjustment, in meters. (output) 485 | * 486 | */ 487 | 488 | void MAG_EquivalentLatLon(double lat, double lon, double *repairedLat, double *repairedLon); 489 | 490 | void MAG_WMMErrorCalc(double H, MAGtype_GeoMagneticElements *Uncertainty); 491 | void MAG_PrintUserDataWithUncertainty(MAGtype_GeoMagneticElements GeomagElements, 492 | MAGtype_GeoMagneticElements Errors, 493 | MAGtype_CoordGeodetic SpaceInput, 494 | MAGtype_Date TimeInput, 495 | MAGtype_MagneticModel *MagneticModel, 496 | MAGtype_Geoid *Geoid); 497 | 498 | 499 | 500 | 501 | #endif /*GEOMAGHEADER_H*/ 502 | -------------------------------------------------------------------------------- /ObjectiveWMM/WMM/PUBLIC_DOMAIN: -------------------------------------------------------------------------------- 1 | The WMM source code is in the public domain and not licensed or under copyright. The information and software may be used freely by the public. As required by 17 U.S.C. 403, third parties producing copyrighted works consisting predominantly of the material produced by U.S. government agencies must provide notice with such work(s) identifying the U.S. Government material incorporated and stating that such material is not subject to copyright protection. 2 | -------------------------------------------------------------------------------- /ObjectiveWMMTests/DeclinationTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DeclinationTests.m 3 | // ObjectiveWMM 4 | // 5 | // Created by Stephen Trainor on 12/15/14. 6 | // Copyright (c) 2014 Crookneck Consulting LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface DeclinationTests : XCTestCase 14 | 15 | @property (nonatomic, strong) NSCalendar *gregorian; 16 | 17 | @end 18 | 19 | @implementation DeclinationTests 20 | 21 | - (NSCalendar *) gregorian { 22 | 23 | if (nil == _gregorian) { 24 | _gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 25 | } 26 | 27 | return _gregorian; 28 | } 29 | 30 | - (void)setUp { 31 | [super setUp]; 32 | // Put setup code here. This method is called before the invocation of each test method in the class. 33 | 34 | // run tests in GMT, overriding local system time zone 35 | [NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithName:@"Etc/GMT"]]; 36 | } 37 | 38 | - (void)tearDown { 39 | // Put teardown code here. This method is called after the invocation of each test method in the class. 40 | [super tearDown]; 41 | } 42 | 43 | - (void) testCoefficientFileFound { 44 | 45 | NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.crookneckconsulting.ObjectiveWMM"]; 46 | NSString *path = [bundle pathForResource:@"WMM" ofType:@"COF"]; 47 | XCTAssertNotNil(path, @"Path to WMM.COF was nil"); 48 | } 49 | 50 | - (void) testModelValidityPeriod { 51 | 52 | // Current model is valid from 2020 through 2025 (see https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml) 53 | 54 | NSDate *validFrom = [self dateForYear:2020 month:1 day:1]; 55 | NSDate *validTo = [self dateForYear:2025 month:12 day:31]; 56 | 57 | XCTAssertTrue([validFrom isEqualToDate:[[CCMagneticModel instance] modelValidityStart]], @"Unexpected model validity start date"); 58 | XCTAssertTrue([validTo isEqualToDate:[[CCMagneticModel instance] modelValidityEnd]], @"Unexpected model validity end date"); 59 | } 60 | 61 | // See https://www.ngdc.noaa.gov/geomag/WMM/data/WMM2020/WMM2020testvalues.pdf for tests 01 through 12 62 | 63 | - (void) testDeclination01 { 64 | 65 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 66 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(80, 0); 67 | 68 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 69 | 70 | NSLog(@"declination = %f", declination.magneticDeclination); 71 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, -1.28, 0.005, @"Unexpected declination"); 72 | 73 | } 74 | 75 | - (void) testDeclination02 { 76 | 77 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 78 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(0, 120); 79 | 80 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 81 | 82 | NSLog(@"declination = %f", declination.magneticDeclination); 83 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 0.16, 0.005, @"Unexpected declination"); 84 | 85 | } 86 | 87 | - (void) testDeclination03 { 88 | 89 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 90 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-80, 240); 91 | 92 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 93 | 94 | NSLog(@"declination = %f", declination.magneticDeclination); 95 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 69.36, 0.005, @"Unexpected declination"); 96 | 97 | } 98 | 99 | - (void) testDeclination04 { 100 | 101 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 102 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(80, 0); 103 | 104 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 105 | 106 | NSLog(@"declination = %f", declination.magneticDeclination); 107 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, -1.70, 0.005, @"Unexpected declination"); 108 | 109 | } 110 | 111 | - (void) testDeclination05 { 112 | 113 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 114 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(0, 120); 115 | 116 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 117 | 118 | NSLog(@"declination = %f", declination.magneticDeclination); 119 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 0.16, 0.005, @"Unexpected declination"); 120 | 121 | } 122 | 123 | - (void) testDeclination06 { 124 | 125 | NSDate *date = [self dateForYear:2020 month:1 day:1]; 126 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-80, 240); 127 | 128 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 129 | 130 | NSLog(@"declination = %f", declination.magneticDeclination); 131 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 68.78, 0.005, @"Unexpected declination"); 132 | 133 | } 134 | 135 | - (void) testDeclination07 { 136 | 137 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 138 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(80, 0); 139 | 140 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 141 | 142 | NSLog(@"declination = %f", declination.magneticDeclination); 143 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 0.01, 0.005, @"Unexpected declination"); 144 | 145 | } 146 | 147 | - (void) testDeclination08 { 148 | 149 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 150 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(0, 120); 151 | 152 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 153 | 154 | NSLog(@"declination = %f", declination.magneticDeclination); 155 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, -0.06, 0.005, @"Unexpected declination"); 156 | 157 | } 158 | 159 | - (void) testDeclination09 { 160 | 161 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 162 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-80, 240); 163 | 164 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:0 date:date]; 165 | 166 | NSLog(@"declination = %f", declination.magneticDeclination); 167 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 69.13, 0.006, @"Unexpected declination"); 168 | 169 | } 170 | 171 | - (void) testDeclination10 { 172 | 173 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 174 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(80, 0); 175 | 176 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 177 | 178 | NSLog(@"declination = %f", declination.magneticDeclination); 179 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, -0.41, 0.005, @"Unexpected declination"); 180 | 181 | } 182 | 183 | - (void) testDeclination11 { 184 | 185 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 186 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(0, 120); 187 | 188 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 189 | 190 | NSLog(@"declination = %f", declination.magneticDeclination); 191 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, -0.05, 0.005, @"Unexpected declination"); 192 | 193 | } 194 | 195 | - (void) testDeclination12 { 196 | 197 | NSDate *date = [self dateForYear:2022 month:7 day:1]; 198 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-80, 240); 199 | 200 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:100000 date:date]; 201 | 202 | NSLog(@"declination = %f", declination.magneticDeclination); 203 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 68.55, 0.005, @"Unexpected declination"); 204 | 205 | } 206 | 207 | // Subsequent test values obtained from WMMGUI: https://www.ngdc.noaa.gov/geomag/WMM/soft.shtml 208 | 209 | - (void) testDeclination13 { 210 | 211 | // Boulder, Colorado on Jan 10 2023 212 | 213 | NSDate *date = [self dateForYear:2023 month:1 day:10]; 214 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 215 | 216 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630.0 date:date]; 217 | 218 | NSLog(@"declination = %f", declination.magneticDeclination); 219 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 7.93, 0.005, @"Unexpected declination"); 220 | 221 | } 222 | 223 | - (void) testDeclination14 { 224 | 225 | // London, UK on Aug 28 2024 226 | 227 | NSDate *date = [self dateForYear:2024 month:8 day:28]; 228 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(51.507335, -0.127683); 229 | 230 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:22.0 date:date]; 231 | 232 | NSLog(@"declination = %f", declination.magneticDeclination); 233 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 0.95, 0.005, @"Unexpected declination"); 234 | 235 | } 236 | 237 | - (void) testDeclination15 { 238 | 239 | // Sydney, Australia on Dec 31 2020 240 | 241 | NSDate *date = [self dateForYear:2020 month:12 day:31]; 242 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-33.867487, 151.206990); 243 | 244 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:54.0 date:date]; 245 | 246 | NSLog(@"declination = %f", declination.magneticDeclination); 247 | XCTAssertEqualWithAccuracy(declination.magneticDeclination, 12.68, 0.005, @"Unexpected declination"); 248 | } 249 | 250 | - (void) testInvalidDate01 { 251 | 252 | // Sydney, Australia on Jan 1 2026 - date is out of model bounds, declination returned should equal zero 253 | 254 | NSDate *date = [self dateForYear:2026 month:1 day:1]; 255 | 256 | XCTAssertFalse([[CCMagneticModel instance] dateIsWithinModelBounds:date], @"Expected date to be out of model bounds"); 257 | 258 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-33.867487, 151.206990); 259 | 260 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:54.0 date:date]; 261 | XCTAssertNil(declination, @"Declination should be nil"); 262 | 263 | } 264 | 265 | - (void) testInvalidDate02 { 266 | 267 | // Sydney, Australia on Dec 31 2019 - date is out of model bounds, declination returned should equal zero 268 | 269 | NSDate *date = [self dateForYear:2019 month:12 day:31]; 270 | 271 | XCTAssertFalse([[CCMagneticModel instance] dateIsWithinModelBounds:date], @"Expected date to be out of model bounds"); 272 | 273 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(-33.867487, 151.206990); 274 | 275 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:54.0 date:date]; 276 | XCTAssertNil(declination, @"Declination should be nil"); 277 | } 278 | 279 | - (void) testTrueHeading01 { 280 | 281 | // Boulder, Colorado on Jan 10 2023 282 | 283 | NSDate *date = [self dateForYear:2023 month:1 day:10]; 284 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 285 | 286 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630.0 date:date]; 287 | 288 | NSLog(@"declination = %f", declination.magneticDeclination); 289 | XCTAssertEqualWithAccuracy([declination trueHeadingFromMagneticHeading:94.0], 94.0 + 7.93, 0.005, @"Unexpected true heading"); 290 | 291 | } 292 | 293 | - (void) testMagneticHeading01 { 294 | 295 | // Boulder, Colorado on Jan 10 2023 296 | 297 | NSDate *date = [self dateForYear:2023 month:1 day:10]; 298 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 299 | 300 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630.0 date:date]; 301 | 302 | NSLog(@"declination = %f", declination.magneticDeclination); 303 | XCTAssertEqualWithAccuracy([declination magneticHeadingFromTrueHeading:94.0 + 7.93], 94.0, 0.005, @"Unexpected magnetic heading"); 304 | 305 | } 306 | 307 | - (void) testDateBounds01 { 308 | 309 | NSDate *date = [self dateForYear:2019 month:8 day:1]; 310 | 311 | NSDate *withinBounds = [[CCMagneticModel instance] dateWithinModelBoundsFromDate:date]; 312 | 313 | XCTAssertTrue([withinBounds isEqualToDate:[[CCMagneticModel instance] modelValidityStart]], @"Unexpected date"); 314 | } 315 | 316 | - (void) testDateBounds02 { 317 | 318 | NSDate *date = [self dateForYear:2027 month:3 day:21]; 319 | 320 | NSDate *withinBounds = [[CCMagneticModel instance] dateWithinModelBoundsFromDate:date]; 321 | 322 | 323 | XCTAssertEqualObjects(date, [withinBounds laterDate:date], @"Unexpected date"); 324 | } 325 | 326 | - (void) testDateBounds03 { 327 | 328 | NSDate *date = [self dateForYear:2021 month:6 day:21]; 329 | 330 | NSDate *withinBounds = [[CCMagneticModel instance] dateWithinModelBoundsFromDate:date]; 331 | 332 | XCTAssertTrue([withinBounds isEqualToDate:date], @"Unexpected date"); 333 | } 334 | 335 | - (void) testDateWithinBounds01 { 336 | 337 | NSDate *inputDate = [self dateForYear:2027 month:1 day:1]; // out of range 338 | 339 | NSDate *dateInBounds = [[CCMagneticModel instance] dateWithinModelBoundsFromDate:inputDate]; 340 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 341 | XCTAssertNotNil([[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630 date:dateInBounds], @"Declination was nil"); 342 | } 343 | 344 | - (void) testDateWithinBounds02 { 345 | 346 | NSDate *inputDate = [self dateForYear:2019 month:1 day:1]; // out of range 347 | 348 | NSDate *dateInBounds = [[CCMagneticModel instance] dateWithinModelBoundsFromDate:inputDate]; 349 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 350 | XCTAssertNotNil([[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630 date:dateInBounds], @"Declination was nil"); 351 | } 352 | 353 | - (void) testHeadingInBounds01 { 354 | 355 | // New York on Jan 10 2023 356 | 357 | NSDate *date = [self dateForYear:2023 month:1 day:10]; 358 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.714353, -74.005973); 359 | 360 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:57.0 date:date]; 361 | double heading = [declination trueHeadingFromMagneticHeading:0.0]; 362 | 363 | NSLog(@"heading = %f", heading); 364 | XCTAssertTrue(0 < heading, @"heading was less than zero"); 365 | XCTAssertTrue(heading < 360, @"heading was greater than 360"); 366 | 367 | } 368 | 369 | - (void) testHeadingInBounds02 { 370 | 371 | // Boulder, Colorado on Jan 10 2023 372 | 373 | NSDate *date = [self dateForYear:2023 month:1 day:10]; 374 | CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(40.014986, -105.270546); 375 | 376 | CCMagneticDeclination *declination = [[CCMagneticModel instance] declinationForCoordinate:coord elevation:1630.0 date:date]; 377 | double heading = [declination magneticHeadingFromTrueHeading:0.0]; 378 | 379 | NSLog(@"heading = %f", heading); 380 | XCTAssertTrue(0 < heading, @"heading was less than zero"); 381 | XCTAssertTrue(heading < 360, @"heading was greater than 360"); 382 | 383 | } 384 | 385 | #pragma mark - Helper methods 386 | 387 | - (NSDate *) dateForYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { 388 | 389 | static NSDateComponents *comps; 390 | if (nil == comps) { 391 | comps = [[NSDateComponents alloc] init]; 392 | } 393 | 394 | [comps setDay:day]; 395 | [comps setMonth:month]; 396 | [comps setYear:year]; 397 | NSDate *date = [self.gregorian dateFromComponents:comps]; 398 | 399 | return date; 400 | } 401 | 402 | @end 403 | -------------------------------------------------------------------------------- /ObjectiveWMMTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | 24 | 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ObjectiveWMM 2 | ============ 3 | 4 | An Objective-C iOS wrapper for the [World Magnetic Model 2020](https://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml). 5 | 6 | ObjectiveWMM is a simple repackaging for iOS of the C-language World Magnetic Model published by the United States’ National Geospatial-Intelligence Agency (NGA) and the United Kingdom’s Defence Geographic Centre (DGC). 7 | 8 | WMM is primarily useful to be able to determine the magnetic declination for a given location on a given date. As the earth's magnetic field changes over time, the model provides a way to obtain a predicted value for magnetic declination. 9 | 10 | Magnetic declination is required in order to convert between headings relative to true north and magnetic north. The difference can be significant in certain parts of the world. 11 | 12 | ## Limitations of CoreLocation 13 | 14 | I suspect that iOS already has the World Magnetic Model built in to the system software. `CLHeading` provides both `magneticHeading` and `trueHeading` properties, where the difference between the values represents the magneticDeclination. However, per Apple's documentation: 15 | 16 | >Typically, you do not create instances of this class yourself, nor do you subclass it. Instead, you receive instances of this class through the delegate assigned to the CLLocationManager object whose startUpdatingHeading method you called. 17 | 18 | The consequence of that is that via CoreLocation, you can only determine magneticDeclination for here (where the device is actually located) and now (the moment you retrieve the `CLHeading` object). 19 | 20 | ## Intended use cases 21 | 22 | Mapping, route-finding and astronomical applications may wish to include magnetic headings for users making use of a magnetic compass in the field. The headings may pertain to places other than the current device location and for dates in the future (or the past). 23 | 24 | In order to obtain, for example, a magnetic heading from a heading relative to true north, ObjectiveWMM can provide the magnetic declination required to make the correction. 25 | 26 | ## Getting Started 27 | 28 | * Download [ObjectiveWMM](https://github.com/stephent/ObjectiveWMM/archive/master.zip) and open the project in Xcode. 29 | * Choose the ObjectiveWMM Target and an iOS Simulator 30 | * Run the selected target and execute the unit tests 31 | 32 | The project is configured as a Dynamic Framework targeting iOS 8.1. The unit tests (using XCTest) demonstrate how to use the classes in the project. 33 | 34 | ## What's included 35 | 36 | ObjectiveWMM includes a copy of the required source files from the original WMM2015 Linux C-language distribution (available [here](http://www.ngdc.noaa.gov/geomag/WMM/soft.shtml)). 37 | 38 | Three additional classes are provided to provide a convenient interface for iOS Objective-C projects: 39 | 40 | * `CCMagneticModel` - a singleton class that initializes the WMM model 41 | * `CCMagneticDeclination` - a result object that holds the calculated magnetic declination for a given coordinate, elevation and date 42 | * `NSDate+DecimalYear` - a category on NSDate to provide decimal date values required as inputs into WMM 43 | 44 | CCMagneticDeclination could optionally be subclassed and extended to return additional model results obtained from the `MAGtype_GeoMagneticElements` struct. (At present, these results are not included as they have more specialized application than the magnetic declination.) 45 | 46 | The ObjectiveWMM target in the project consists of an empty iOS application. This may be extended in the future. For the time being, the unit tests are your best guide. 47 | 48 | ## Test cases 49 | 50 | The project includes a number of unit tests that utilize the [WMM2020 Test Values](https://www.ngdc.noaa.gov/geomag/WMM/data/WMM2020/WMM2020testvalues.pdf) provided by the original model authors. 51 | 52 | In addition, a small number of test cases have been added, with test results taken from the DoD World Magnetic Model [Single Point Calculator](http://www.ngdc.noaa.gov/geomag-web/#igrfwmm) (2020 - 2025), configured to use WMM (2019-2024). 53 | 54 | Finally, tests are included to validate model boundary dates. WMM 2020 is intended for use with dates falling in the years 2020-2025 only. 55 | 56 | ## Modifications to WMM source 57 | 58 | Only two minor changes have been made to the WMM source code included with this project. In the file GeomagnetismHeader.h, 59 | 60 | #define TRUE ((int)1) 61 | #define FALSE ((int)0) 62 | 63 | was changed to: 64 | 65 | #ifndef TRUE 66 | #define TRUE ((int)1) 67 | #endif 68 | 69 | #ifndef FALSE 70 | #define FALSE ((int)0) 71 | #endif 72 | 73 | in order to avoid compiler warnings about redefining TRUE and FALSE. 74 | 75 | ## Credits 76 | 77 | The World Magnetic Model is a joint product of the United States’ National Geospatial-Intelligence Agency (NGA) and the United Kingdom’s Defence Geographic Centre (DGC). The WMM was developed jointly by the National Geophysical Data Center (NGDC, Boulder CO, USA) and the British Geological Survey (BGS, Edinburgh, Scotland). 78 | 79 | ObjectiveWMM by [stephentrainor](https://github.com/stephent/). 80 | 81 | ## License 82 | 83 | ObjectiveWMM includes portions of the WMM source code distributed by NCEI. 84 | 85 | The WMM source code is in the public domain and not licensed or under copyright. The information and software may be used freely by the public. As required by 17 U.S.C. 403, third parties producing copyrighted works consisting predominantly of the material produced by U.S. government agencies must provide notice with such work(s) identifying the U.S. Government material incorporated and stating that such material is not subject to copyright protection. 86 | 87 | The remaining source code in ObjectiveWMM is available under the MIT license. See the LICENSE file for more info. 88 | 89 | 90 | --------------------------------------------------------------------------------