package org.opensha2.geo; import static org.opensha2.geo.Locations.azimuthRad; import static org.opensha2.geo.Locations.horzDistance; import static org.opensha2.geo.Locations.vertDistance; import org.opensha2.util.Maths; /** * This class encapsulates information describing a vector between two * {@code Location}s. Internally, this vector is defined by the azimuth * (bearing) and the horizontal and vertical separation between the points. Note * that a {@code LocationVector} from point A to point B is not the complement * of that from point B to A. Although the horizontal and vertical components * will be the same, the azimuth will likely change by some value other than * 180°. * * <p><b>NOTE:</b> Although a {@code LocationVector} will function in any * reference frame, the convention in seismology and that adopted in OpenSHA is * for depth to be positive down. Also, azimuth is stored internally in radians * for computational convenience. Be sure to use the {@link #azimuth()} * (radians) or // {@link #azimuthDegrees()} (decimal-degrees) where * appropriate. * * @author Peter Powers */ public class LocationVector { private double azimuth; private double vert; private double horiz; private LocationVector(double azimuth, double horiz, double vert) { // TODO validation?? class may be suitable for garbage in/out this.azimuth = azimuth; this.horiz = horiz; this.vert = vert; } /** * Initializes a new {@code LocationVector} with the supplied values. Note * that {@code azimuth} is expected in <i>radians</i>. * * @param azimuth to set in <i>radians</i> * @param horizontal component to set in km * @param vertical component to set in km * @return a new {@code LocationVector} */ public static LocationVector create(double azimuth, double horizontal, double vertical) { return new LocationVector(azimuth, horizontal, vertical); } /** * Creates a new {@code LocationVector} with horizontal and vertical * components derived from the supplied {@code plunge} and {@code length}. * Note that {@code azimuth} and {@code plunge} are expected in * <i>radians</i>. * * @param azimuth to set in <i>radians</i> * @param plunge to set in <i>radians</i> * @param length of vector in km * @return a new {@code LocationVector} */ public static LocationVector createWithPlunge(double azimuth, double plunge, double length) { return create(azimuth, length * Math.cos(plunge), length * Math.sin(plunge)); } /** * Returns the {@code LocationVector} describing the move from one * {@code Location} to another. * * @param p1 the first {@code Location} * @param p2 the second {@code Location} * @return a new {@code LocationVector} */ public static LocationVector create(Location p1, Location p2) { // NOTE A 'fast' implementation of this method was tested // but no performance gain was realized P.Powers 3-5-2010 return create(azimuthRad(p1, p2), horzDistance(p1, p2), vertDistance(p1, p2)); } /** * Returns a copy of the supplied vector with azimuth and vertical components * reversed. * * <p><b>NOTE</b>: create(p1, p2) is not equivalent to create * reverseOf(create(p2, p1)). Although the horizontal and vertical components * will likley be the same but the azimuths will potentially be different. * * @param v {@code LocationVector} to copy and flip * @return the flipped copy */ public static LocationVector reverseOf(LocationVector v) { return create((v.azimuth + Math.PI) % Maths.TWOPI, v.horiz, -v.vert); } /** * Returns the azimuth of this vector in decimal degrees. * @return the azimuth in decimal degrees * @see #azimuth() */ public double azimuthDegrees() { return azimuth * Maths.TO_DEG; } /** * Returns the azimuth of this vector in radians. * @return the azimuth in radians * @see #azimuthDegrees() */ public double azimuth() { return azimuth; } /** * Returns the angle (in radians) between this vector and a horizontal plane. * This method is intended for use at relatively short separations (e.g. * ≤200km) as it degrades at large distances where curvature is not * considered. Note that positive angles are down, negative angles are up. * @return the plunge of this vector */ public double plunge() { return Math.atan(vert / horiz); } /** * Returns the angle (in decimal degrees) between this vector and a horizontal * plane. This method is intended for use at relatively short separations * (e.g. ≤200km) as it degrades at large distances where curvature is not * considered. Note that positive angles are down, negative angles are up. * @return the plunge of this vector */ public double plungeDegrees() { return plunge() * Maths.TO_DEG; } /** * Returns the vertical component of this vector. * @return the vertical component in km */ public double vertical() { return vert; } /** * Returns the horizontal component of this vector. * @return the horizontal component in km */ public double horizontal() { return horiz; } @Override public String toString() { StringBuffer b = new StringBuffer(); b.append(this.getClass().getSimpleName()); b.append(": az = "); b.append(azimuthDegrees()); b.append(" dH = "); b.append(horiz); b.append(" dV = "); b.append(vert); return b.toString(); } }