001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.util.imagery;
003
004import java.awt.geom.Point2D;
005
006/**
007 * A utility class for mapping a point onto a spherical coordinate system and vice versa
008 * @since 18246
009 */
010public final class UVMapping {
011    private static final double TWO_PI = 2 * Math.PI;
012    private UVMapping() {
013        // Private constructor to avoid instantiation
014    }
015
016    /**
017     * Returns the point of the texture image that is mapped to the given point in 3D space (given as {@link Vector3D})
018     * See <a href="https://en.wikipedia.org/wiki/UV_mapping">the Wikipedia article on UV mapping</a>.
019     *
020     * @param vector the vector to which the texture point is mapped
021     * @return a point on the texture image somewhere in the rectangle between (0, 0) and (1, 1)
022     */
023    public static Point2D.Double getTextureCoordinate(final Vector3D vector) {
024        final double u = 0.5 + (Math.atan2(vector.getX(), vector.getZ()) / TWO_PI);
025        final double v = 0.5 + (Math.asin(vector.getY()) / Math.PI);
026        return new Point2D.Double(u, v);
027    }
028
029    /**
030     * For a given point of the texture (i.e. the image), return the point in 3D space where the point
031     * of the texture is mapped to (as {@link Vector3D}).
032     *
033     * @param u x-coordinate of the point on the texture (in the range between 0 and 1, from left to right)
034     * @param v y-coordinate of the point on the texture (in the range between 0 and 1, from top to bottom)
035     * @return the vector from the origin to where the point of the texture is mapped on the sphere
036     */
037    public static Vector3D getVector(final double u, final double v) {
038        if (u > 1 || u < 0 || v > 1 || v < 0) {
039            throw new IllegalArgumentException("u and v must be between or equal to 0 and 1");
040        }
041        final double vectorY = Math.cos(v * Math.PI);
042        final double vectorYSquared = Math.pow(vectorY, 2);
043        return new Vector3D(-Math.sin(TWO_PI * u) * Math.sqrt(1 - vectorYSquared), -vectorY,
044            -Math.cos(TWO_PI * u) * Math.sqrt(1 - vectorYSquared));
045    }
046}