All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tomtom.speedtools.tilemap.MercatorPoint Maven / Gradle / Ivy

/*
 * Copyright (C) 2012-2021, TomTom (http://tomtom.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tomtom.speedtools.tilemap;

import com.tomtom.speedtools.geometry.GeoPoint;
import com.tomtom.speedtools.json.Json;
import com.tomtom.speedtools.utils.MathUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import java.util.Arrays;

/**
 * Mercator point. Specified in X and Y with normalized values of 0..1 (top-left to bottom-right).
 *
 * Constructor: {@link #MercatorPoint}
 */
@Immutable
public final class MercatorPoint {
    private final double mercX;
    private final double mercY;

    /**
     * Create a normalized Mercator pair.
     *
     * @param mercX X coordinate of Mercator pair. Range 0..1, 0 = lon -180, 1 = lon 180.
     * @param mercY Y coordinate of Mercator pair. Range 0..1, 0 = lat 90, 1 = lat -90.
     */
    MercatorPoint(
            final double mercX,
            final double mercY) {
        super();
        assert MathUtils.isBetween(mercX, 0.0, 1.0) : mercX;
        assert MathUtils.isBetween(mercY, 0.0, 1.0) : mercY;
        this.mercX = mercX;
        this.mercY = mercY;
    }

    public double getMercX() {
        return mercX;
    }

    public double getMercY() {
        return mercY;
    }

    /**
     * Return lat/lon, given normalized Mercator points. Mercator points are defined as (x, y), where x = 0..1
     * (left/lon=-180 to right/lon=180) and y = 0..1 (top/lat=90 to bottom/lat=-90).
     *
     * @param mercX X, 0..1 (lon -180..180).
     * @param mercY Y, 0..1 (lat 90..-90).
     * @return Lat/lon.
     */
    @Nonnull
    public static GeoPoint mercsToLatLon(final double mercX, final double mercY) {
        assert MathUtils.isBetween(mercX, 0.0, 1.0) : mercX;
        assert MathUtils.isBetween(mercY, 0.0, 1.0) : mercY;

        final double geoX = (mercX - 0.5) * MapConst.WORLD_SIZE;
        final double geoY = (mercY - 0.5) * -MapConst.WORLD_SIZE;
        final double lat = (Math.toDegrees(Math.atan(Math.exp(geoY / MapConst.WORLD_RADIUS))) * 2.0) - 90.0;
        final double lon = Math.toDegrees(geoX / MapConst.WORLD_RADIUS);
        return new GeoPoint(lat, lon);
    }

    @Nonnull
    public static GeoPoint mercsToLatLon(@Nonnull final MercatorPoint mercs) {
        return mercsToLatLon(mercs.mercX, mercs.mercY);
    }

    /**
     * Return normalized Mercator points (0..1) for a latitude/longitude. Mercator points are defined as (x, y), where x
     * = 0..1 (left/lon=-180 to right/lon=180) and y = 0..1 (top/lat=90 to bottom/lat=-90).
     *
     * @param point lat/lon.
     * @return Normalized Mercator points.
     */
    @Nonnull
    public static MercatorPoint latLonToMercs(@Nonnull final GeoPoint point) {
        final double lat = MathUtils.limitTo(point.getLat(), MapConst.LATITUDE_MIN, MapConst.LATITUDE_MAX);
        final double lon = point.getLon();
        final double geoX = Math.toRadians(MapConst.WORLD_RADIUS * lon);
        final double geoY = MapConst.WORLD_RADIUS * Math.log(Math.tan(Math.toRadians(lat + 90.0) / 2.0));
        final double mercX = Math.min(1.0, Math.max(0.0, (geoX / MapConst.WORLD_SIZE) + 0.5));
        final double mercY = Math.min(1.0, Math.max(0.0, 1.0 - ((geoY / MapConst.WORLD_SIZE) + 0.5)));
        assert MathUtils.isBetween(mercX, 0.0, 1.0) : mercX + ", " + point;
        assert MathUtils.isBetween(mercY, 0.0, 1.0) : mercY + ", " + point;
        return new MercatorPoint(mercX, mercY);
    }

    @Nonnull
    public static MercatorPoint latLonToMercs(final double lat, final double lon) {
        return latLonToMercs(new GeoPoint(lat, lon));
    }

    public boolean canEqual(@Nonnull final Object obj) {
        return obj instanceof MercatorPoint;
    }

    @Override
    public boolean equals(@Nullable final Object obj) {
        boolean eq;
        if (this == obj) {
            eq = true;
        } else if ((obj != null) && (obj instanceof MercatorPoint)) {
            final MercatorPoint that = (MercatorPoint) obj;
            eq = that.canEqual(this);
            // Top-level entity, so don't: super.equals(that)
            eq = eq && (Double.compare(mercX, that.mercX) == 0);
            eq = eq && (Double.compare(mercY, that.mercY) == 0);
        } else {
            eq = false;
        }

        return eq;
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(new Double[]{mercX, mercY});
    }

    @Override
    public String toString() {
        return Json.toStringJson(this);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy