All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.util.EGM96 Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.util;

import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.exception.WWRuntimeException;
import gov.nasa.worldwind.geom.Angle;

import java.io.*;

/**
 * Computes EGM96 geoid offsets.
 * 

* A file with the offset grid must be passed to the constructor. This file must have 721 rows of 1440 2-byte integer * values. Each row corresponding to a latitude, with the first row corresponding to +90 degrees (90 North). The integer * values must be in centimeters. *

* Once constructed, the instance can be passed to {@link gov.nasa.worldwind.globes.EllipsoidalGlobe#applyEGMA96Offsets(String)} * to apply the offets to elevations produced by the globe. * * @author tag * @version $Id: EGM96.java 770 2012-09-13 02:48:23Z tgaskins $ */ public class EGM96 { protected String offsetsFilePath; protected BufferWrapper deltas; /** * Construct an instance. * * @param offsetsFilePath a path pointing to a file with the geoid offsets. See the class description above for a * description of the file. */ public EGM96(String offsetsFilePath) throws IOException { if (offsetsFilePath == null) { String msg = Logging.getMessage("nullValue.PathIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.offsetsFilePath = offsetsFilePath; this.loadOffsetFile(); } protected void loadOffsetFile() throws IOException { InputStream is = WWIO.openFileOrResourceStream(this.offsetsFilePath, EGM96.class); if (is == null) { String msg = Logging.getMessage("generic.CannotOpenFile", this.offsetsFilePath); Logging.logger().severe(msg); throw new WWRuntimeException(msg); } try { AVList bufferParams = new AVListImpl(); bufferParams.setValue(AVKey.DATA_TYPE, AVKey.INT16); bufferParams.setValue(AVKey.BYTE_ORDER, AVKey.BIG_ENDIAN); this.deltas = BufferWrapper.wrap(WWIO.readStreamToBuffer(is, true), bufferParams); } catch (IOException e) { String msg = Logging.getMessage("generic.ExceptionAttemptingToReadFile", this.offsetsFilePath); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); throw e; } finally { WWIO.closeStream(is, this.offsetsFilePath); } } // Description of the EGMA96 offsets file: // See http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/binary/binarygeoid.html // The total size of the file is 2,076,480 bytes. This file was created // using an INTEGER*2 data type format and is an unformatted direct access // file. The data on the file is arranged in records from north to south. // There are 721 records on the file starting with record 1 at 90 N. The // last record on the file is at latitude 90 S. For each record, there // are 1,440 15 arc-minute geoid heights arranged by longitude from west to // east starting at the Prime Meridian (0 E) and ending 15 arc-minutes west // of the Prime Meridian (359.75 E). On file, the geoid heights are in units // of centimeters. While retrieving the Integer*2 values on file, divide by // 100 and this will produce a geoid height in meters. protected static Angle INTERVAL = Angle.fromDegrees(15d / 60d); // 15' angle delta protected static int NUM_ROWS = 721; protected static int NUM_COLS = 1440; public double getOffset(Angle latitude, Angle longitude) { if (latitude == null || longitude == null) { String msg = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // Return 0 for all offsets if the file failed to load. A log message of the failure will have been generated // by the load method. if (this.deltas == null) return 0; double lat = latitude.degrees; double lon = longitude.degrees >= 0 ? longitude.degrees : longitude.degrees + 360; int topRow = (int) ((90 - lat) / INTERVAL.degrees); if (lat <= -90) topRow = NUM_ROWS - 2; int bottomRow = topRow + 1; // Note that the number of columns does not repeat the column at 0 longitude, so we must force the right // column to 0 for any longitude that's less than one interval from 360, and force the left column to the // last column of the grid. int leftCol = (int) (lon / INTERVAL.degrees); int rightCol = leftCol + 1; if (lon >= 360 - INTERVAL.degrees) { leftCol = NUM_COLS - 1; rightCol = 0; } double latBottom = 90 - bottomRow * INTERVAL.degrees; double lonLeft = leftCol * INTERVAL.degrees; double ul = this.gePostOffset(topRow, leftCol); double ll = this.gePostOffset(bottomRow, leftCol); double lr = this.gePostOffset(bottomRow, rightCol); double ur = this.gePostOffset(topRow, rightCol); double u = (lon - lonLeft) / INTERVAL.degrees; double v = (lat - latBottom) / INTERVAL.degrees; double pll = (1.0 - u) * (1.0 - v); double plr = u * (1.0 - v); double pur = u * v; double pul = (1.0 - u) * v; double offset = pll * ll + plr * lr + pur * ur + pul * ul; return offset / 100d; // convert centimeters to meters } protected double gePostOffset(int row, int col) { int k = row * NUM_COLS + col; if (k >= this.deltas.length()) System.out.println(k); return this.deltas.getInt(k); } // // public static void main(String[] args) // { // EGM96 egm96 = new EGM96("config/EGM96.dat"); // // LatLon latLon = LatLon.fromDegrees(46.166195, -94.405447); //// double offset = egm96.getOffset(latLon.getLatitude(), latLon.getLongitude()); //// double offset = egm96.getOffset(Angle.NEG90, Angle.POS360); // double offset = egm96.getOffset(Angle.fromDegrees(-89.9), Angle.fromDegrees(359.9)); // System.out.println(offset / 100); // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy