Esri / spatial-framework-for-hadoop

The Spatial Framework for Hadoop allows developers and data scientists to use the Hadoop data processing system for spatial data analysis.
Apache License 2.0
363 stars 160 forks source link

I wrote ST_Project following the same syntax as hive esri spatial function, but the result is the not exactly the same #152

Closed fragrantic closed 3 years ago

fragrantic commented 6 years ago

import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.io.BytesWritable; import org.apache.hadoop.hive.serde2.io.DoubleWritable; import com.esri.core.geometry.ogc.OGCGeometry; import com.esri.core.geometry.ogc.OGCPoint; import com.esri.hadoop.hive.GeometryUtils; import com.esri.core.geometry.Point;

public class ST_Project extends UDF { final DoubleWritable resultDouble = new DoubleWritable();

static double EARTH_RADIUS = 6378137.0;

static double degToRad(double deg) {
    return (deg * Math.PI) / 180.0;
}

static double radToDeg(double rad) {
    return (rad * 180.0) / Math.PI;
}

static double x;
static double y;

public static BytesWritable evaluate(BytesWritable geom, double distance, double bearing) {

    if (geom == null) {
        return null;
    }

    try {

    double angular = distance / EARTH_RADIUS;
    double bearingRad = degToRad(bearing);
    OGCGeometry Geometry = GeometryUtils.geometryFromEsriShape(geom);
    OGCPoint pt1 = (OGCPoint)Geometry;      
    double latRad = degToRad(((OGCPoint) pt1).X());
    double lonRad = degToRad(((OGCPoint) pt1).Y());
    double a = Math.sin((latRad));
    double b = Math.cos((angular));
    double c = Math.cos((latRad));
    double d = Math.sin((angular));
    double e = Math.cos((bearingRad));

    double lat = Math.asin(((a * b) + (c * d * e)));

    double f = Math.sin((bearingRad));
    double h = Math.sin((lat));
    double i = (f * d * c);
    double j = (b - (a * h));

    double lon = lonRad + Math.atan2(i, j);

    x = radToDeg(lon);
    y = radToDeg(lat);

    DoubleWritable x1 = new DoubleWritable(x);
    DoubleWritable y1 = new DoubleWritable(y);

    Point stPt = new Point(y1.get(),x1.get());

    BytesWritable ret = GeometryUtils.geometryToEsriShapeBytesWritable(OGCGeometry.createFromEsriGeometry(stPt, null));

    return ret;
    } catch (Exception e) {
        return null;} } }
randallwhitman commented 6 years ago

On what input? What is the expected result? What is the actual result?

fragrantic commented 6 years ago

If you are familiar white postgis which is a spatial extension of postgres, it comes with a lot of spatial function one of them being ST_Project, ST_Project — Returns a POINT projected from a start point using a distance in meters and bearing (azimuth) in radians. Now if I were to execute this function like this : select st_astext(st_project(st_point(0,0), 100000, radians(45))) I get this as a result: Point(0.63523085373227,0.6351918164606) And if you were to do the same thing in postgres I get this : Point(0.635231029125537,0.639472334729198)

randallwhitman commented 6 years ago

The code posted in the description on 05/14 appears to have calculations for a sphere, which is a fast approximation, but not entirely accurate, for an oblate spheroid such as the Earth.

fragrantic commented 6 years ago

So what am I supposed to do ?

randallwhitman commented 6 years ago

If the question is how to use a Geometry API to apply a geodesic displacement, you might try asking under the Esri Geometry API for Java or at a general programming Q&A forum.

fragrantic commented 6 years ago

Thank you I will do so

randallwhitman commented 6 years ago

https://github.com/Esri/geometry-api-java/issues/175