001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.coor;
003
004import java.io.Serializable;
005import java.util.Objects;
006
007/**
008 * Polar coordinate.
009 * @since 13107 (extracted from {@code AlignInCircleAction})
010 */
011public class PolarCoor implements Serializable {
012
013    private static final long serialVersionUID = 1L;
014
015    /**
016     * Radial coordinate (distance from the pole).
017     */
018    public final double radius;
019
020    /**
021     * Angular coordinate in radians.
022     */
023    public final double angle;
024
025    /**
026     * Reference point (analogous to the origin of a Cartesian coordinate system).
027     */
028    public final EastNorth pole;
029
030    /**
031     * Constructs a new {@code PolarCoor}, using {@code (0,0)} as pole.
032     * @param radius radial coordinate (distance from the pole)
033     * @param angle angular coordinate in radians
034     */
035    public PolarCoor(double radius, double angle) {
036        this(radius, angle, new EastNorth(0, 0));
037    }
038
039    /**
040     * Constructs a new {@code PolarCoor}.
041     * @param radius radial coordinate (distance from the pole)
042     * @param angle angular coordinate in radians
043     * @param pole reference point (analogous to the origin of a Cartesian coordinate system)
044     */
045    public PolarCoor(double radius, double angle, EastNorth pole) {
046        this.radius = radius;
047        this.angle = angle;
048        this.pole = pole;
049    }
050
051    /**
052     * Constructs a new {@code PolarCoor} from an {@link EastNorth}, using {@code (0,0)} as pole.
053     * @param en east/north coordinates
054     */
055    public PolarCoor(EastNorth en) {
056        this(en, new EastNorth(0, 0));
057    }
058
059    /**
060     * Constructs a new {@code PolarCoor}.
061     * @param en east/north coordinates
062     * @param pole reference point (analogous to the origin of a Cartesian coordinate system)
063     */
064    public PolarCoor(EastNorth en, EastNorth pole) {
065        this(en.distance(pole), computeAngle(en, pole), pole);
066    }
067
068    /**
069     * Compute polar angle between an east/north and the pole.
070     * @param en east/north coordinates
071     * @param pole reference point (analogous to the origin of a Cartesian coordinate system)
072     * @return polar angle in radians
073     */
074    public static double computeAngle(EastNorth en, EastNorth pole) {
075        return Math.atan2(en.north() - pole.north(), en.east() - pole.east());
076    }
077
078    /**
079     * Converts this {@code PolarCoor} to an {@link EastNorth} instance.
080     * @return a new {@code EastNorth} instance
081     */
082    public EastNorth toEastNorth() {
083        return new EastNorth(
084                radius * Math.cos(angle) + pole.east(),
085                radius * Math.sin(angle) + pole.north());
086    }
087
088    @Override
089    public int hashCode() {
090        return Objects.hash(radius, angle, pole);
091    }
092
093    @Override
094    public boolean equals(Object obj) {
095        if (this == obj) return true;
096        if (obj == null || getClass() != obj.getClass()) return false;
097        PolarCoor that = (PolarCoor) obj;
098        return Double.compare(that.radius, radius) == 0 &&
099               Double.compare(that.angle, angle) == 0 &&
100               Objects.equals(that.pole, pole);
101    }
102
103    @Override
104    public String toString() {
105        return "PolarCoor [radius=" + radius + ", angle=" + angle + ", pole=" + pole + ']';
106    }
107}