X-Git-Url: http://pileus.org/git/?p=grits;a=blobdiff_plain;f=src%2Fgrits-util.c;h=ab795f9b15ae41c7e1c86884e2655ca8383371c1;hp=634f132a8def927a2c02fe05f59cf1caeaa82359;hb=HEAD;hpb=d8948985b467a5cfd0447ae413ed1c5d01afb024 diff --git a/src/grits-util.c b/src/grits-util.c index 634f132..ab795f9 100644 --- a/src/grits-util.c +++ b/src/grits-util.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Andy Spencer + * Copyright (C) 2009-2011 Andy Spencer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ */ /** - * SECTION:gis-util + * SECTION:grits-util * @short_description: Geographic utilities * * Miscellaneous utility functions, these deal mostly with coordinate @@ -70,14 +70,15 @@ #include #include +#include #include "grits-util.h" -/************ - * GisPoint * - ************/ +/************** + * GritsPoint * + **************/ /** - * gis_point_set_lle: + * grits_point_set_lle: * @point: the point to modify * @lat: the new latitude * @lon: the new longitude @@ -85,7 +86,7 @@ * * Set the latitude, longitude, and elevation for a point. */ -void gis_point_set_lle(GisPoint *point, gdouble lat, gdouble lon, gdouble elev) +void grits_point_set_lle(GritsPoint *point, gdouble lat, gdouble lon, gdouble elev) { point->lat = lat; point->lon = lon; @@ -93,11 +94,11 @@ void gis_point_set_lle(GisPoint *point, gdouble lat, gdouble lon, gdouble elev) } -/************* - * GisBounds * - *************/ +/*************** + * GritsBounds * + ***************/ /** - * gis_bounds_set_bounds: + * grits_bounds_set_bounds: * @n: the north edge * @s: the south edge * @e: the east edge @@ -105,7 +106,7 @@ void gis_point_set_lle(GisPoint *point, gdouble lat, gdouble lon, gdouble elev) * * Set the north, south, east, and west edges of the bounding box */ -void gis_bounds_set_bounds(GisBounds *bounds, +void grits_bounds_set_bounds(GritsBounds *bounds, gdouble n, gdouble s, gdouble e, gdouble w) { bounds->n = n; @@ -235,3 +236,153 @@ gdouble lon_avg(gdouble a, gdouble b) } return avg; } + +/** + * crossd3: + * @a: the left point + * @b: the center point + * @c: the right point + * @out: the cross product + * + * Calculate the cross product of three points + */ +void crossd3(gdouble *a, gdouble *b, gdouble *c, gdouble *out) +{ + double ba[3], bc[3]; + + ba[0] = a[0] - b[0]; + ba[1] = a[1] - b[1]; + ba[2] = a[2] - b[2]; + + bc[0] = c[0] - b[0]; + bc[1] = c[1] - b[1]; + bc[2] = c[2] - b[2]; + + crossd(ba, bc, out); +} + +/** + * crossd: + * @a: the first vector + * @b: the second vector + * @c: the cross product + * + * Calculate the cross product of two vectors + */ +void crossd(gdouble *a, gdouble *b, gdouble *out) +{ + out[0] = a[1] * b[2] - a[2] * b[1]; + out[1] = a[2] * b[0] - a[0] * b[2]; + out[2] = a[0] * b[1] - a[1] * b[0]; +} + +/** + * lengthd: + * @a: the vector + * + * Calculate the length (magnitude) of a vector. + * + * Returns: the length + */ +gdouble lengthd(gdouble *a) +{ + return sqrt(a[0] * a[0] + + a[1] * a[1] + + a[2] * a[2]); +} + +/** + * normd: + * @a: the first longitude + * + * Normalize a vector to a mangitude of 1 + */ +void normd(gdouble *a) +{ + gdouble total = lengthd(a); + a[0] = a[0] / total; + a[1] = a[1] / total; + a[2] = a[2] / total; +} + +/** + * parse_points: + * @string: String representation of the points + * @group_sep: Group separator + * @point_sep: Point separator + * @coord_sep: Coordinate separator + * @bounds: The bounding box of all the points, or NULL + * @center: The center of the @bounds, or NULL + * + * Parse a string of the form: + * string -> group [@group_sep group] ... + * group -> point [@point_sep point] ... + * point -> latitude @coord_sep longitude [@coord_sep elevation] + * + * For example + * parse_points("30,-80 30,-120 50,-120 50,-80", "\t", " ", ","); + * + * Returns: zero-terminated array of groups of points + */ +GritsPoints *parse_points(const gchar *string, + const gchar *group_sep, const gchar *point_sep, const gchar *coord_sep, + GritsBounds *bounds, GritsPoint *center) +{ + /* Split and count groups */ + gchar **sgroups = g_strsplit(string, group_sep, -1); + int ngroups = g_strv_length(sgroups); + + GritsBounds _bounds = {-90, 90, -180, 180}; + gdouble (**groups)[3] = (gpointer)g_new0(double*, ngroups+1); + for (int pi = 0; pi < ngroups; pi++) { + /* Split and count coordinates */ + gchar **scoords = g_strsplit(sgroups[pi], point_sep, -1); + int ncoords = g_strv_length(scoords); + + /* Create binary coords */ + gdouble (*coords)[3] = (gpointer)g_new0(gdouble, 3*(ncoords+1)); + for (int ci = 0; ci < ncoords; ci++) { + gdouble lat, lon; + sscanf(scoords[ci], "%lf,%lf", &lat, &lon); + if (bounds || center) { + if (lat > _bounds.n) _bounds.n = lat; + if (lat < _bounds.s) _bounds.s = lat; + if (lon > _bounds.e) _bounds.e = lon; + if (lon < _bounds.w) _bounds.w = lon; + } + lle2xyz(lat, lon, 0, + &coords[ci][0], + &coords[ci][1], + &coords[ci][2]); + } + + /* Insert coords into line array */ + groups[pi] = coords; + g_strfreev(scoords); + } + g_strfreev(sgroups); + + /* Output */ + if (bounds) + *bounds = _bounds; + if (center) { + center->lat = (_bounds.n + _bounds.s)/2; + center->lon = lon_avg(_bounds.e, _bounds.w); + center->elev = 0; + } + return groups; +} + +/** + * free_points: + * @points: Array of points allocated by parse_points() + * + * Frees all data allocated by parse_points + */ +void free_points(GritsPoints *points) +{ + gdouble (**_points)[3] = points; + for (int i = 0; _points[i]; i++) + g_free(_points[i]); + g_free(_points); +}