Hive 中自定义函数实现墨卡托和经纬度相互转换

2019-11-24  本文已影响0人  lei_charles
package com.cloudera.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

import java.text.DecimalFormat;


/**
 * 经纬度和墨卡托相互转换
 */
 @Description(name = "mercator_lnglat_convert",
        value = "mercator_lnglat_convert(String a , String b, boolean flag) ==> return result ",
        extended = "Example:\n"
                + " mercator_lnglat_convert(\"12727039.383734727\", \"3579066.6894065146\") ==> \"114.3289400||30.5857480\" \n"
                + " mercator_lnglat_convert(\"12727039.383734727\", \"3579066.6894065146\", true) ==> \"114.3289400||30.5857480\" \n"
                + " mercator_lnglat_convert(\"12727039.383734727\", \"3579066.6894065146\", 7) ==> \"114.3289400||30.5857480\" \n"
                + " mercator_lnglat_convert(\"12727039.383734727\", \"3579066.6894065146\", true, 9) ==> \"114.328940016||30.585748004\" \n"
                + " mercator_lnglat_convert(\"114.32894\", \"30.585748\", false, 9) ==> \"12727039.383734727||3404789.892891386\";"
)
public class MercatorAndLngLatInterconversion extends UDF {

    /**
     * 地球半径
     */
    private final static double EARTH_RADIUS = 6378137.0;

    private final static double EARTH_SEMI_PERIMETER = 20037508.34;

    private final static int DEFAULT_LEN = 7;

    private final Text result = new Text();

    /**
     * @param flag  true 为经纬度转墨卡托,false  为墨卡托转经纬度
     * @param num   保留小数点后面的位数
     */
    public Text evaluate(String value1, String value2, boolean flag, int num) {
        String x = "";
        String y = "";
        try {
            String pattern = "#." + String.format("%0" + num + "d", 0);
            DecimalFormat format = new DecimalFormat(pattern);
            if (flag) {
                x = format.format(getLng(Double.valueOf(value1)));
                y = format.format(getLat(Double.valueOf(value2)));
            } else {
                x = format.format(getMercatorX(Double.valueOf(value1)));
                y = format.format(getMercatorX(Double.valueOf(value2)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        result.set(x + "||" + y);
        return result;
    }

    public Text evaluate(String value1, String value2) {
        return evaluate(value1, value2, true, DEFAULT_LEN);
    }

    public Text evaluate(String value1, String value2, int num) {
        return evaluate(value1, value2, true, num);
    }
    public Text evaluate(String value1, String value2, boolean flag) {
        return evaluate(value1, value2, flag, DEFAULT_LEN);
    }

    /**
     * 经度转墨卡托坐标 X
     */
    private double getMercatorX(double lng) {
        double mercator_X = lng * Math.PI / 180 * EARTH_RADIUS;
        return mercator_X;
    }

    /**
     * 纬度转墨卡托坐标 Y
     */
    private double getMercatorY(double lat) {
        double a = lat * Math.PI / 180;
        double mercator_Y = EARTH_RADIUS / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
        return mercator_Y;
    }

    /**
     * 墨卡托转经度
     */
    private double getLng(double poi_X) {
        double lng = poi_X / EARTH_SEMI_PERIMETER * 180;
        return lng;
    }

    /**
     * 墨卡托转纬度
     */
    private double getLat(double poi_Y) {
        double mmy = poi_Y / EARTH_SEMI_PERIMETER * 180;
        double lat = 180 / Math.PI * (2 * Math.atan(Math.exp(mmy * Math.PI / 180)) - Math.PI / 2);
        return lat;
    }
}
上一篇下一篇

猜你喜欢

热点阅读