001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.coor;
003
004/**
005 * Northing, Easting of the projected coordinates.
006 *
007 * This class is immutable.
008 *
009 * @author Imi
010 */
011public class EastNorth extends Coordinate {
012
013    private static final long serialVersionUID = 1L;
014
015    /**
016     * Constructs a new {@code EastNorth}.
017     * @param east easting
018     * @param north northing
019     */
020    public EastNorth(double east, double north) {
021        super(east, north);
022    }
023
024    /**
025     * Returns easting.
026     * @return easting
027     */
028    public double east() {
029        return x;
030    }
031
032    /**
033     * Returns northing.
034     * @return northing
035     */
036    public double north() {
037        return y;
038    }
039
040    /**
041     * Adds an offset to this {@link EastNorth} instance and returns the result.
042     * @param dEast The offset to add in east direction.
043     * @param dNorth The offset to add in north direction.
044     * @return The result.
045     */
046    public EastNorth add(double dEast, double dNorth) {
047        return new EastNorth(east()+dEast, north()+dNorth);
048    }
049
050    /**
051     * Adds the coordinates of an other EastNorth instance to this one.
052     * @param other The other instance.
053     * @return The new EastNorth position.
054     */
055    public EastNorth add(EastNorth other) {
056        return new EastNorth(x+other.x, y+other.y);
057    }
058
059    /**
060     * Subtracts an east/north value from this point.
061     * @param other The other value to subtract from this.
062     * @return A point with the new coordinates.
063     */
064    public EastNorth subtract(EastNorth other) {
065        return new EastNorth(x-other.x, y-other.y);
066    }
067
068    /**
069     * Scales this {@link EastNorth} instance to a given factor and returns the result.
070     * @param s factor
071     * @return The result.
072     */
073    public EastNorth scale(double s) {
074        return new EastNorth(s * x, s * y);
075    }
076
077    /**
078     * Does a linear interpolation between two EastNorth instances.
079     * @param en2 The other EstNort instance.
080     * @param proportion The proportion the other instance influences the result.
081     * @return The new {@link EastNorth} position.
082     */
083    public EastNorth interpolate(EastNorth en2, double proportion) {
084        // this is an alternate form of this.x + proportion * (en2.x - this.x) that is slightly faster
085        return new EastNorth((1 - proportion) * this.x + proportion * en2.x,
086                (1 - proportion) * this.y + proportion * en2.y);
087    }
088
089    /**
090     * Gets the center between two {@link EastNorth} instances.
091     * @param en2 The other instance.
092     * @return The center between this and the other instance.
093     */
094    public EastNorth getCenter(EastNorth en2) {
095        // The JIT will inline this for us, it is as fast as the normal /2 approach
096        return interpolate(en2, .5);
097    }
098
099    /**
100     * Returns the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}.
101     *
102     * @param en the specified coordinate to be measured against this {@code EastNorth}
103     * @return the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}
104     * @since 6166
105     */
106    public double distance(final EastNorth en) {
107        return super.distance(en);
108    }
109
110    /**
111     * Returns the square of the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}.
112     *
113     * @param en the specified coordinate to be measured against this {@code EastNorth}
114     * @return the square of the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}
115     * @since 6166
116     */
117    public double distanceSq(final EastNorth en) {
118        return super.distanceSq(en);
119    }
120
121    /**
122     * Counts length (distance from [0,0]) of this.
123     *
124     * @return length of this
125     */
126    public double length() {
127        return Math.sqrt(x*x + y*y);
128    }
129
130    /**
131     * Returns the heading, in radians, that you have to use to get from
132     * this EastNorth to another. Heading is mapped into [0, 2pi)
133     *
134     * @param other the "destination" position
135     * @return heading
136     */
137    public double heading(EastNorth other) {
138        double hd = Math.atan2(other.east() - east(), other.north() - north());
139        if (hd < 0) {
140            hd = 2 * Math.PI + hd;
141        }
142        return hd;
143    }
144
145    /**
146     * Replies true if east and north are different from Double.NaN and not infinite
147     *
148     * @return true if east and north are different from Double.NaN and not infinite
149     */
150    public boolean isValid() {
151        return !Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y);
152    }
153
154    /**
155     * Returns an EastNorth representing the this EastNorth rotated around
156     * a given EastNorth by a given angle
157     * @param pivot the center of the rotation
158     * @param angle the angle of the rotation
159     * @return EastNorth rotated object
160     */
161    public EastNorth rotate(EastNorth pivot, double angle) {
162        double cosPhi = Math.cos(angle);
163        double sinPhi = Math.sin(angle);
164        double x = east() - pivot.east();
165        double y = north() - pivot.north();
166        // CHECKSTYLE.OFF: SingleSpaceSeparator
167        double nx =  cosPhi * x + sinPhi * y + pivot.east();
168        double ny = -sinPhi * x + cosPhi * y + pivot.north();
169        // CHECKSTYLE.ON: SingleSpaceSeparator
170        return new EastNorth(nx, ny);
171    }
172
173    @Override
174    public String toString() {
175        return "EastNorth[e="+x+", n="+y+']';
176    }
177
178    /**
179     * Compares two EastNorth values
180     * @param other other east.north
181     * @param e epsilon
182     *
183     * @return true if "x" and "y" values are within epsilon {@code e} of each other
184     */
185    public boolean equalsEpsilon(EastNorth other, double e) {
186        return Math.abs(x - other.x) < e && Math.abs(y - other.y) < e;
187    }
188}