Index: gcg/gcg_gmap_views.module
===================================================================
--- gcg/gcg_gmap_views.module (revision 89)
+++ gcg/gcg_gmap_views.module (working copy)
@@ -118,4 +118,97 @@
return $output;
break;
}
-}
\ No newline at end of file
+}
+
+
+function gcg_gmap_views_views_arguments() {
+ $arguments = array(
+ 'gcg_gmap_views_arg_proximity' => array(
+ 'name' => t('GCG GMAP: Nodes within proximity'),
+ 'handler' => 'gcg_gmap_views_arg_proximity',
+ 'option' => 'string',
+ 'help' => t('Within distance of defined lat and long, set Option to latitude,longitude,distance, ie: -90.00,23.45,5km '),
+ )
+ );
+
+ return $arguments;
+}
+
+
+/**
+ * Process the comma-seperate argument into an assoc array
+ *
+ * Note: You could use this to provide a whole markup system for doing clever things
+ * - ie ",nid: 300" find nodes within distance from this
+ * ",uid: 22" nodes close to this user
+ *
+ * @param string $arg
+ */
+function _gcg_gmap_views_arg_process($arg) {
+
+ $tmp=explode(',',urldecode($arg));
+ if(!is_array($tmp) || sizeof($tmp)<2) {
+ return false;
+ }
+
+ // basic sanity check, replace anything not a digit, a decimal or a - with ''
+ $proximity_info['lat']=preg_replace('/[^\d\.-]/i','',$tmp[0]);
+ $proximity_info['lon']=preg_replace('/[^\d\.-]/i','',$tmp[1]);
+
+ if(sizeof($tmp)>2) {
+ $proximity_info['unit']=eregi('mi$',$tmp[2]) ? 'miles' : 'kilometers';
+ $proximity_info['distance']=preg_replace('/[^\d\.]/i','',$tmp[2]);
+ } else {
+ // default to something
+ $proximity_info['distance']=50;
+ $proximity_info['unit']='kilometers';
+ }
+
+ return $proximity_info;
+}
+
+/**
+ * GCG GMAP Views argument handler
+ *
+ * note: this uses earth.inc from location module, which is a really inefficient and mathematically
+ * expensive way todo things, BUT IT DOES WORK.
+ *
+ * @param unknown_type $op
+ * @param unknown_type $query
+ * @param unknown_type $argtype
+ * @param unknown_type $arg
+ * @param unknown_type $table
+ */
+function gcg_gmap_views_arg_proximity($op, &$query, $argtype, $arg = '', $table = 'gcg_views') {
+
+ // ensure this doesnt collide with locations module's include of earth.inc
+ if(! function_exists('earth_latitude_range') ) {
+ $module_path = drupal_get_path('module', 'gcg_gmap_views');
+ include_once($module_path.'/earth.inc');
+ }
+
+ switch($op) {
+ case 'filter':
+ $_info = _gcg_gmap_views_arg_process($arg);
+ if(!is_array($_info) || !strlen($_info['lat']) || !strlen($_info['lon']) || ! strlen($_info['distance'])) {
+ drupal_set_message('Invalid Longitude, Latitude or Distance defined.');
+ return;
+ }
+
+ $divisor = $_info['unit'] == 'kilometers' ? 1000 : 1609.347;
+ $latrange = earth_latitude_range($_info['lon'], $_info['lat'], ($_info['distance'] * $divisor));
+ $lonrange = earth_longitude_range($_info['lon'], $_info['lat'], ($_info['distance'] * $divisor));
+
+ // a large enough distance will cause the earth function to pass something bad to asin()
+ if( is_nan($latrange[0]) || is_nan($lonrange[0]) ) {
+ drupal_set_message('Unable to calculate items within that distance, please specify a smaller radius to check within.');
+ return;
+ }
+ $query->ensure_table($table);
+ $query->add_orderby(NULL, "((". earth_distance_sql($_info['lon'], $_info['lat'],$table) .") / $divisor)", 'ASC', 'distance');
+ $query->add_where("$table.longitude IS NOT NULL");
+ $query->add_where("$table.latitude > %f AND $table.latitude < %f AND $table.longitude > %f AND $table.longitude < %f", $latrange[0], $latrange[1], $lonrange[0], $lonrange[1]);
+ break;
+ }
+
+}
Index: gcg/earth.inc
===================================================================
--- gcg/earth.inc (revision 0)
+++ gcg/earth.inc (revision 103)
@@ -0,0 +1,155 @@
+ pi()) { $maxlong = $maxlong - pi()*2; }
+ return array(rad2deg($minlong), rad2deg($maxlong));
+}
+
+function earth_latitude_range($longitude, $latitude, $distance) {
+ // Estimate the min and max latitudes within $distance of a given location.
+ $long = deg2rad($longitude);
+ $lat = deg2rad($latitude);
+ $radius = earth_radius($latitude);
+
+ $angle = $distance / $radius;
+ $minlat = $lat - $angle;
+ $maxlat = $lat + $angle;
+ $rightangle = pi()/2;
+ if ($minlat < -$rightangle) { // wrapped around the south pole
+ $overshoot = -$minlat - $rightangle;
+ $minlat = -$rightangle + $overshoot;
+ if ($minlat > $maxlat) { $maxlat = $minlat; }
+ $minlat = -$rightangle;
+ }
+ if ($maxlat > $rightangle) { // wrapped around the north pole
+ $overshoot = $maxlat - $rightangle;
+ $maxlat = $rightangle - $overshoot;
+ if ($maxlat < $minlat) { $minlat = $maxlat; }
+ $maxlat = $rightangle;
+ }
+ return array(rad2deg($minlat), rad2deg($maxlat));
+}
+
+?>