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    public EastNorth(double east, double north) {
016        super(east, north);
017    }
018
019    public double east() {
020        return x;
021    }
022
023    public double north() {
024        return y;
025    }
026
027    /**
028     * Adds an offset to this {@link EastNorth} instance and returns the result.
029     * @param dEast The offset to add in east direction.
030     * @param dNorth The offset to add in north direction.
031     * @return The result.
032     */
033    public EastNorth add(double dEast, double dNorth) {
034        return new EastNorth(east()+dEast, north()+dNorth);
035    }
036
037    /**
038     * Adds the coordinates of an other EastNorth instance to this one.
039     * @param other The other instance.
040     * @return The new EastNorth position.
041     */
042    public EastNorth add(EastNorth other) {
043        return new EastNorth(x+other.x, y+other.y);
044    }
045
046    /**
047     * Subtracts an east/north value from this point.
048     * @param other The other value to subtract from this.
049     * @return A point with the new coordinates.
050     */
051    public EastNorth subtract(EastNorth other) {
052        return new EastNorth(x-other.x, y-other.y);
053    }
054
055    public EastNorth scale(double s) {
056        return new EastNorth(s * x, s * y);
057    }
058
059    /**
060     * Does a linear interpolation between two EastNorth instances.
061     * @param en2 The other EstNort instance.
062     * @param proportion The proportion the other instance influences the result.
063     * @return The new {@link EastNorth} position.
064     */
065    public EastNorth interpolate(EastNorth en2, double proportion) {
066        return new EastNorth(this.x + proportion * (en2.x - this.x),
067                this.y + proportion * (en2.y - this.y));
068    }
069
070    /**
071     * Gets the center between two {@link EastNorth} instances.
072     * @param en2 The other instance.
073     * @return The center between this and the other instance.
074     */
075    public EastNorth getCenter(EastNorth en2) {
076        return new EastNorth((this.x + en2.x)/2.0, (this.y + en2.y)/2.0);
077    }
078
079    /**
080     * Returns the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}.
081     *
082     * @param en the specified coordinate to be measured against this {@code EastNorth}
083     * @return the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}
084     * @since 6166
085     */
086    public double distance(final EastNorth en) {
087        return super.distance(en);
088    }
089
090    /**
091     * Returns the square of the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}.
092     *
093     * @param en the specified coordinate to be measured against this {@code EastNorth}
094     * @return the square of the euclidean distance from this {@code EastNorth} to a specified {@code EastNorth}
095     * @since 6166
096     */
097    public double distanceSq(final EastNorth en) {
098        return super.distanceSq(en);
099    }
100
101    /**
102     * Counts length (distance from [0,0]) of this.
103     *
104     * @return length of this
105     */
106    public double length() {
107        return Math.sqrt(x*x + y*y);
108    }
109
110    /**
111     * Returns the heading, in radians, that you have to use to get from
112     * this EastNorth to another. Heading is mapped into [0, 2pi)
113     *
114     * @param other the "destination" position
115     * @return heading
116     */
117    public double heading(EastNorth other) {
118        double hd = Math.atan2(other.east() - east(), other.north() - north());
119        if (hd < 0) {
120            hd = 2 * Math.PI + hd;
121        }
122        return hd;
123    }
124
125    /**
126     * Replies true if east and north are different from Double.NaN and not infinite
127     *
128     * @return true if east and north are different from Double.NaN and not infinite
129     */
130    public boolean isValid() {
131        return !Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y);
132    }
133
134    /**
135     * Returns an EastNorth representing the this EastNorth rotated around
136     * a given EastNorth by a given angle
137     * @param pivot the center of the rotation
138     * @param angle the angle of the rotation
139     * @return EastNorth rotated object
140     */
141    public EastNorth rotate(EastNorth pivot, double angle) {
142        double cosPhi = Math.cos(angle);
143        double sinPhi = Math.sin(angle);
144        double x = east() - pivot.east();
145        double y = north() - pivot.north();
146        double nx =  cosPhi * x + sinPhi * y + pivot.east();
147        double ny = -sinPhi * x + cosPhi * y + pivot.north();
148        return new EastNorth(nx, ny);
149    }
150
151    @Override
152    public String toString() {
153        return "EastNorth[e="+x+", n="+y+']';
154    }
155
156    /**
157     * Compares two EastNorth values
158     * @param other other east.north
159     * @param e epsilon
160     *
161     * @return true if "x" and "y" values are within epsilon {@code e} of each other
162     */
163    public boolean equalsEpsilon(EastNorth other, double e) {
164        return Math.abs(x - other.x) < e && Math.abs(y - other.y) < e;
165    }
166}