Changeset: bf48f38d5105 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/bf48f38d5105
Modified Files:
        geom/monetdb5/geom.c
Branch: geo-update
Log Message:

Distance for geographies now calculates the perpendicular of a point in a line.


diffs (165 lines):

diff --git a/geom/monetdb5/geom.c b/geom/monetdb5/geom.c
--- a/geom/monetdb5/geom.c
+++ b/geom/monetdb5/geom.c
@@ -123,6 +123,14 @@ static void geog2cart(double lon, double
        (*z) = sin(lat);
 }
 
+static void geog2cart_r(double lon, double lat, double *x, double *y, double 
*z)
+{
+       double r = 6371.009;
+       (*x) = r * cos(lat) * cos(lon);
+       (*y) = r * cos(lat) * sin(lon);
+       (*z) = r * sin(lat);
+}
+
 /**
 * Convert cartesian coordinates on unit sphere to spherical coordinates
 * From PostGIS
@@ -133,6 +141,13 @@ static void geog2cart(double lon, double
        (*lat) = asin(z);
 }*/
 
+static void cart2geog_r(double x, double y, double z, double *lon, double *lat)
+{
+       double r = 6371.009;
+       (*lon) = atan2(y, x);
+       (*lat) = asin(z / r);
+}
+
 /* Returns the latitude and longitude (in radians) from a geographic Geom 
point */
 static void pointToRadian(GEOSGeom geom, double *lat_r, double *lon_r)
 {
@@ -183,12 +198,45 @@ static double geoDistancePointPoint(GEOS
        return haversine(lat1_r, lon1_r, lat2_r, lon2_r);
 }
 
-//TODO -> First try in geom_todo.c
-static double calculatePerpendicular(GEOSGeom a, GEOSGeom b)
-{
-       a = NULL;
-       b = NULL;
-       return INT_MAX;
+//TODO Improve this function, there may be a easier way (vector operations?)
+//TODO Check if changing the g2c_r function to g2c makes any difference
+static double calculatePerpendicular(GEOSGeom p, GEOSGeom l)
+{
+       //p is the point, a is the start of the line and b is the end of the 
line
+       double a_lat, a_lon, a_x, a_y, a_z, b_lat, b_lon, b_x, b_y, b_z, p_lat, 
p_lon, p_x, p_y, p_z;
+       //First, we convert the points to 3D cartesian coordinates
+       pointToRadian(GEOSGeomGetStartPoint(l), &a_lat, &a_lon);
+       geog2cart_r(a_lon, a_lat, &a_x, &a_y, &a_z);
+       pointToRadian(GEOSGeomGetEndPoint(l), &b_lat, &b_lon);
+       geog2cart_r(b_lon, b_lat, &b_x, &b_y, &b_z);
+       pointToRadian(p, &p_lat, &p_lon);
+       geog2cart_r(p_lon, p_lat, &p_x, &p_y, &p_z);
+
+       //Calculate the projection of point into the line
+       double d_ab = (b_z - a_z) * (b_z - a_z) + (b_y - a_y) * (b_y - a_y) + 
(b_x - a_x) * (b_x - a_x);
+       double t = (((p_x - a_x) * (b_x - a_x)) + ((p_y - a_y) * (b_y - a_y)) + 
((p_z - a_z) * (b_z - a_z))) / d_ab;
+
+       //TODO Check if this is correct
+       //If t is not between 0 and 1, the projected point is not in the line, 
so there is no perpendicular
+       if (t < 0 || t > 1)
+               return INT_MAX;
+
+       double proj_x, proj_y, proj_z, proj_lat, proj_lon;
+       proj_x = a_x + t * (b_x - a_x);
+       proj_y = a_y + t * (b_y - a_y);
+       proj_z = a_z + t * (b_z - a_z);
+
+       //Convert into geographic coordinates
+       cart2geog_r(proj_x, proj_y, proj_z, &proj_lon, &proj_lat);
+       proj_lon = proj_lon * 180.0 / M_PI;
+       proj_lat = proj_lat * 180.0 / M_PI;
+
+       /*printf("a = (%f %f %f)\nb = (%f %f %f)\np = (%f %f %f)\ndab = %f\nt = 
%f\n", a_x, a_y, a_z, b_x, b_y, b_z, p_x, p_y, p_z, d_ab, t);
+       printf("proj = (%f %f %f) -> (%f %f)\nDistance = %f\n\n", proj_x, 
proj_y, proj_z, proj_lon, proj_lat, distance);
+       fflush(stdout);*/
+
+       //Calculate distance from original point to the projection
+       return geoDistancePointPoint(p, GEOSGeom_createPointFromXY(proj_lon, 
proj_lat));
 }
 
 /* Distance between Point and a simple Line (only one Line segment) */
@@ -197,7 +245,6 @@ static double geoDistancePointLineSingle
        double distancePerpendicular, distanceStart, distanceEnd;
 
        /* Calculate perpendicular of point in Line */
-       //TODO Implement this correctly
        distancePerpendicular = calculatePerpendicular(point, line);
 
        /* Calculate distance of point to start and end points of line */
@@ -220,6 +267,7 @@ static double geoDistancePointLineSingle
 }
 
 /* Given a Line/LinearRing geometry with multiple segments and the index to 
fetch, returns a single Line segment */
+//TODO Is there a better way to do this?
 static GEOSGeometry *getLineSegment(GEOSCoordSequence *multiLineCoords, int 
segmentIndex)
 {
        double x1, y1, x2, y2;
@@ -284,6 +332,21 @@ static double geoDistanceLineLine(GEOSGe
        return min_distance;
 }
 
+/*static void pointOutsidePolygon(GEOSGeom polygon, double *lon_outside, 
double *lat_outside)
+{
+       mbr *bbox = mbrFromGeos((const GEOSGeom)polygon);
+       printf("X: (%f %f)\nY: (%f %f)\n", bbox->xmin, bbox->xmax, bbox->ymin, 
bbox->ymax);
+       double x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
+       geog2cart_r(bbox->xmin, bbox->ymin, &x1, &y1, &z1);
+       geog2cart_r(bbox->xmin, bbox->ymax, &x2, &y2, &z2);
+       geog2cart_r(bbox->xmax, bbox->ymin, &x3, &y3, &z3);
+       geog2cart_r(bbox->xmax, bbox->ymax, &x4, &y4, &z4);
+       printf("Points:\n(%f %f %f)\n(%f %f %f)\n(%f %f %f)\n(%f %f %f)\n\n", 
x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
+       fflush(stdout);
+       lon_outside = NULL;
+       lat_outside = NULL;
+}*/
+
 //TODO Check if this works always
 //For fast testing, we could use the polygon's minimum bounding box
 static bool pointWithinPolygonRing(GEOSGeom point, GEOSGeom polygon)
@@ -296,6 +359,8 @@ static bool pointWithinPolygonRing(GEOSG
        //Get an point that's outside the polygon
        //TODO Get the outside point using the polygon's bounding box, instead 
of being static
        double lat_o = 48.193, lon_o = -4.551;
+       /*double lat_out, lon_out;
+       pointOutsidePolygon(polygon, &lon_out, &lat_out);*/
 
        //Construct a line between the outside point and the input point
        GEOSGeomGetX(point, &lon_p);
@@ -369,7 +434,7 @@ static double geoDistanceLinePolygon(GEO
 }
 
 /* Distance between two Polygons. */
-//TODO Check if we can simply use the LinePolygon function (does it work with 
polygon with holes?)
+//TODO Check if we can simply use the LinePolygon function
 static double geoDistancePolygonPolygon(GEOSGeom polygon1, GEOSGeom polygon2)
 {
        const GEOSGeometry *polygon_ring;
@@ -526,6 +591,11 @@ str wkbIntersectsGeographic(bit *out, wk
        return err;
 }
 
+/**
+* End of Geographic update code
+*
+**/
+
 int TYPE_mbr;
 
 static wkb *geos2wkb(const GEOSGeometry *geosGeometry);
@@ -7371,9 +7441,9 @@ static mel_atom geom_init_atoms[] = {
        },
        {.cmp = NULL}};
 static mel_func geom_init_funcs[] = {
-       command("geom", "DWithinGeographic", wkbDWithinGeographic, false, 
"TODO", args(1, 4, arg("", dbl), arg("a", wkb), arg("b", wkb), arg("d", dbl))),
-       command("geom", "IntersectsGeographic", wkbIntersectsGeographic, false, 
"Returns true if the geographic Geometries intersect in any point", args(1, 3, 
arg("", dbl), arg("a", wkb), arg("b", wkb))),
-       command("geom", "DistanceGeographic", wkbDistanceGeographic, false, 
"TODO", args(1, 3, arg("", bit), arg("a", wkb), arg("b", wkb))),
+       command("geom", "DWithinGeographic", wkbDWithinGeographic, false, 
"TODO", args(1, 4, arg("", bit), arg("a", wkb), arg("b", wkb), arg("d", dbl))),
+       command("geom", "IntersectsGeographic", wkbIntersectsGeographic, false, 
"Returns true if the geographic Geometries intersect in any point", args(1, 3, 
arg("", bit), arg("a", wkb), arg("b", wkb))),
+       command("geom", "DistanceGeographic", wkbDistanceGeographic, false, 
"TODO", args(1, 3, arg("", dbl), arg("a", wkb), arg("b", wkb))),
        command("geom", "hasZ", geoHasZ, false, "returns 1 if the geometry has 
z coordinate", args(1, 2, arg("", int), arg("flags", int))),
        command("geom", "hasM", geoHasM, false, "returns 1 if the geometry has 
m coordinate", args(1, 2, arg("", int), arg("flags", int))),
        command("geom", "getType", geoGetType, false, "returns the str 
representation of the geometry type", args(1, 3, arg("", str), arg("flags", 
int), arg("format", int))),
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to