]> Pileus Git - grits/blobdiff - src/grits-util.c
Add cube GtkGL example
[grits] / src / grits-util.c
index d42cee59d1a33c9c2b06e3950a49258ad0548b8c..ab795f9b15ae41c7e1c86884e2655ca8383371c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
+ * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
  *
  * 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
 
 #include <glib.h>
 #include <math.h>
+#include <stdio.h>
 
-#include "gis-util.h"
+#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);
+}