griffordson-georuby-extras 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +11 -0
- data/README +77 -0
- data/ext/extconf.rb +3 -0
- data/ext/pnpoly.c +105 -0
- data/ext/pnpoly.h +6 -0
- data/ext/vincenty.c +166 -0
- data/lib/georuby-extras.rb +46 -0
- data/test/test_pnpoly.rb +35 -0
- data/test/test_vincenty.rb +42 -0
- metadata +96 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
= georuby-extras
|
2
|
+
|
3
|
+
* http://github.com/davetroy/georuby-extras
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
GeoRuby-Extras Gem for Ruby (c) 2008 David Troy
|
8
|
+
dave@roundhousetech.com
|
9
|
+
|
10
|
+
GeoRuby-Extras offers some native C enhancements and extras to the popular GeoRuby gem.
|
11
|
+
|
12
|
+
GeoRuby offers OGC-compliant simple features for Ruby as well as the ability to
|
13
|
+
process SHP files and do other cool GIS hacks. GeoRuby is often used in conjunction
|
14
|
+
with GIS extensions for popular databases including Postgres and MySQL.
|
15
|
+
|
16
|
+
== FEATURES/PROBLEMS:
|
17
|
+
|
18
|
+
* Provides native C implementation of Vincenty distance and direct algorithms.
|
19
|
+
* 25 times faster than GeoRuby 'ellipsoidal_distance' function.
|
20
|
+
* Adds the Vincenty 'direct' algorithm (point_at_bearing_and_distance).
|
21
|
+
* Provides native C implementation of a ray casting algorithm to detect if a point is contained in a polygon.
|
22
|
+
* No known problems; won't work with JRuby or non-MRI Ruby implementations.
|
23
|
+
|
24
|
+
== SYNOPSIS:
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'georuby-extras'
|
28
|
+
|
29
|
+
include GeoRuby::SimpleFeatures
|
30
|
+
|
31
|
+
@home = Point.from_lon_lat(-76.511,39.024)
|
32
|
+
@nyc = Point.from_lon_lat(-74,40.6)
|
33
|
+
|
34
|
+
>> @home.ellipsoidal_distance(@nyc)
|
35
|
+
=> 277195.510448391
|
36
|
+
|
37
|
+
>> @home.point_at_bearing_and_distance(91.0, 130000.0).kml_representation
|
38
|
+
=> "<Point>\n<coordinates>-75.0105920700835,38.9939120193168</coordinates>\n</Point>\n"
|
39
|
+
|
40
|
+
== REQUIREMENTS:
|
41
|
+
|
42
|
+
* GCC and a Gnu-ish build environment (for native extensions)
|
43
|
+
|
44
|
+
== INSTALLATION
|
45
|
+
|
46
|
+
1) Update to the latest RubyGems version
|
47
|
+
> gem update --system
|
48
|
+
|
49
|
+
2) Install gem
|
50
|
+
> gem install griffordson-georuby-extras
|
51
|
+
|
52
|
+
3) Profit!
|
53
|
+
|
54
|
+
== LICENSE:
|
55
|
+
|
56
|
+
(The MIT License)
|
57
|
+
|
58
|
+
Copyright (c) 2008 David Troy, Roundhouse Technologies LLC
|
59
|
+
|
60
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
61
|
+
a copy of this software and associated documentation files (the
|
62
|
+
'Software'), to deal in the Software without restriction, including
|
63
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
64
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
65
|
+
permit persons to whom the Software is furnished to do so, subject to
|
66
|
+
the following conditions:
|
67
|
+
|
68
|
+
The above copyright notice and this permission notice shall be
|
69
|
+
included in all copies or substantial portions of the Software.
|
70
|
+
|
71
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
72
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
73
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
74
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
75
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
76
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
77
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/ext/extconf.rb
ADDED
data/ext/pnpoly.c
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
// pnpoly.c
|
2
|
+
// (c) 2010 Matt Griffith
|
3
|
+
//
|
4
|
+
// A native Ruby extension for determining if a point is in a polygon.
|
5
|
+
//
|
6
|
+
// (The MIT License)
|
7
|
+
//
|
8
|
+
// Copyright (c) 2010 Matt Griffith, AgriSmart Information Systems, LLC
|
9
|
+
//
|
10
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
11
|
+
// a copy of this software and associated documentation files (the
|
12
|
+
// 'Software'), to deal in the Software without restriction, including
|
13
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
14
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
15
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
16
|
+
// the following conditions:
|
17
|
+
//
|
18
|
+
// The above copyright notice and this permission notice shall be
|
19
|
+
// included in all copies or substantial portions of the Software.
|
20
|
+
//
|
21
|
+
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
22
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
23
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
24
|
+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
25
|
+
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
26
|
+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
27
|
+
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
|
+
//
|
29
|
+
// --------------------------------------------------------
|
30
|
+
// The pnpoly function is covered by the following license.
|
31
|
+
// For more inforation see:
|
32
|
+
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
33
|
+
//
|
34
|
+
// Copyright (c) 1970-2003, Wm. Randolph Franklin
|
35
|
+
//
|
36
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
37
|
+
// a copy of this software and associated documentation files (the
|
38
|
+
// "Software"), to deal in the Software without restriction, including
|
39
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
40
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
41
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
42
|
+
// the following conditions:
|
43
|
+
//
|
44
|
+
// Redistributions of source code must retain the above copyright
|
45
|
+
// notice, this list of conditions and the following disclaimers.
|
46
|
+
// Redistributions in binary form must reproduce the above copyright
|
47
|
+
// notice in the documentation and/or other materials provided with the
|
48
|
+
// distribution. The name of W. Randolph Franklin may not be used to
|
49
|
+
// endorse or promote products derived from this Software without
|
50
|
+
// specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS",
|
51
|
+
// WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
52
|
+
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
53
|
+
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
54
|
+
// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
55
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
56
|
+
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
57
|
+
// OTHER DEALINGS IN THE SOFTWARE.
|
58
|
+
|
59
|
+
#include "ruby.h"
|
60
|
+
#include "pnpoly.h"
|
61
|
+
|
62
|
+
static int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
|
63
|
+
{
|
64
|
+
int i, j, c = 0;
|
65
|
+
for (i = 0, j = nvert-1; i < nvert; j = i++) {
|
66
|
+
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
|
67
|
+
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
|
68
|
+
c = !c;
|
69
|
+
}
|
70
|
+
return c;
|
71
|
+
}
|
72
|
+
|
73
|
+
VALUE point_in_poly(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_points) {
|
74
|
+
Check_Type(rb_x, T_FLOAT);
|
75
|
+
Check_Type(rb_y, T_FLOAT);
|
76
|
+
Check_Type(rb_points, T_ARRAY);
|
77
|
+
|
78
|
+
int i = 0;
|
79
|
+
int s = RARRAY(rb_points)->len;
|
80
|
+
float *vertx;
|
81
|
+
float *verty;
|
82
|
+
|
83
|
+
vertx = calloc(s, sizeof(float));
|
84
|
+
verty = calloc(s, sizeof(float));
|
85
|
+
|
86
|
+
float test_x = RFLOAT(rb_x)->value;
|
87
|
+
float test_y = RFLOAT(rb_y)->value;
|
88
|
+
|
89
|
+
ID i_x = rb_intern("x");
|
90
|
+
ID i_y = rb_intern("y");
|
91
|
+
|
92
|
+
for(i = 0; i < s; i++) {
|
93
|
+
VALUE point = RARRAY_PTR(rb_points)[i];
|
94
|
+
VALUE x = rb_funcall(point, i_x, 0);
|
95
|
+
VALUE y = rb_funcall(point, i_y, 0);
|
96
|
+
Check_Type(x, T_FLOAT);
|
97
|
+
Check_Type(y, T_FLOAT);
|
98
|
+
vertx[i] = RFLOAT(x)->value;
|
99
|
+
verty[i] = RFLOAT(y)->value;
|
100
|
+
}
|
101
|
+
|
102
|
+
return pnpoly(s, vertx, verty, test_x, test_y);
|
103
|
+
}
|
104
|
+
|
105
|
+
// end
|
data/ext/pnpoly.h
ADDED
data/ext/vincenty.c
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
// geohash-native.c
|
2
|
+
// (c) 2008 David Troy
|
3
|
+
// dave@roundhousetech.com
|
4
|
+
//
|
5
|
+
// Based on Javascript code (c) by Chris Veness
|
6
|
+
// http://www.movable-type.co.uk/scripts/latlong-vincenty.html
|
7
|
+
// http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
|
8
|
+
//
|
9
|
+
// Derived from algorithms by T. Vincenty, 1975
|
10
|
+
//
|
11
|
+
// (The MIT License)
|
12
|
+
//
|
13
|
+
// Copyright (c) 2008 David Troy, Roundhouse Technologies LLC
|
14
|
+
//
|
15
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
16
|
+
// a copy of this software and associated documentation files (the
|
17
|
+
// 'Software'), to deal in the Software without restriction, including
|
18
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
19
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
20
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
21
|
+
// the following conditions:
|
22
|
+
//
|
23
|
+
// The above copyright notice and this permission notice shall be
|
24
|
+
// included in all copies or substantial portions of the Software.
|
25
|
+
//
|
26
|
+
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
27
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
28
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
29
|
+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
30
|
+
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
31
|
+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
32
|
+
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
33
|
+
|
34
|
+
#include "ruby.h"
|
35
|
+
#include <math.h>
|
36
|
+
#include <ctype.h>
|
37
|
+
#include "pnpoly.h"
|
38
|
+
|
39
|
+
#define DEG_TO_RAD 0.0174532925199433
|
40
|
+
#define PI 3.14159265358979
|
41
|
+
|
42
|
+
static VALUE rb_mVincenty;
|
43
|
+
static VALUE rb_mPointInPoly;
|
44
|
+
|
45
|
+
static VALUE distance(VALUE self, VALUE rb_lon1, VALUE rb_lat1, VALUE rb_lon2, VALUE rb_lat2, VALUE rb_a, VALUE rb_b) {
|
46
|
+
|
47
|
+
Check_Type(rb_lon1, T_FLOAT);
|
48
|
+
Check_Type(rb_lat1, T_FLOAT);
|
49
|
+
Check_Type(rb_lon2, T_FLOAT);
|
50
|
+
Check_Type(rb_lat2, T_FLOAT);
|
51
|
+
Check_Type(rb_a, T_FLOAT);
|
52
|
+
Check_Type(rb_b, T_FLOAT);
|
53
|
+
|
54
|
+
double lon1 = RFLOAT(rb_lon1)->value;
|
55
|
+
double lat1 = RFLOAT(rb_lat1)->value;
|
56
|
+
double lon2 = RFLOAT(rb_lon2)->value;
|
57
|
+
double lat2 = RFLOAT(rb_lat2)->value;
|
58
|
+
double a = RFLOAT(rb_a)->value;
|
59
|
+
double b = RFLOAT(rb_b)->value;
|
60
|
+
|
61
|
+
double sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, C;
|
62
|
+
|
63
|
+
double f = (a-b) / a;
|
64
|
+
double L = (lon2-lon1) * DEG_TO_RAD;
|
65
|
+
double U1 = atan((1-f) * tan(lat1 * DEG_TO_RAD));
|
66
|
+
double U2 = atan((1-f) * tan(lat2 * DEG_TO_RAD));
|
67
|
+
double sinU1 = sin(U1), cosU1 = cos(U1);
|
68
|
+
double sinU2 = sin(U2), cosU2 = cos(U2);
|
69
|
+
|
70
|
+
int iterLimit = 20;
|
71
|
+
double lambda = L, lambdaP=2*PI;
|
72
|
+
while ((fabs(lambda-lambdaP) > 1e-12 && --iterLimit>0)) {
|
73
|
+
sinLambda = sin(lambda); cosLambda = cos(lambda);
|
74
|
+
sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
|
75
|
+
if (sinSigma==0) return rb_float_new(0); // co-incident points
|
76
|
+
cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
|
77
|
+
sigma = atan2(sinSigma, cosSigma);
|
78
|
+
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
|
79
|
+
cosSqAlpha = 1 - sinAlpha*sinAlpha;
|
80
|
+
cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
|
81
|
+
if (isnan(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6)
|
82
|
+
C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
|
83
|
+
lambdaP = lambda;
|
84
|
+
lambda = L + (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
|
85
|
+
}
|
86
|
+
|
87
|
+
if (iterLimit==0) return Qnil; // formula failed to converge
|
88
|
+
|
89
|
+
double uSq = cosSqAlpha * (a*a - b*b) / (b*b);
|
90
|
+
double A = 1 + uSq/16384.0*(4096+uSq*(-768+uSq*(320-175*uSq)));
|
91
|
+
double B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
|
92
|
+
double deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM) -
|
93
|
+
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
|
94
|
+
|
95
|
+
double s = b*A*(sigma-deltaSigma);
|
96
|
+
|
97
|
+
return rb_float_new(s);
|
98
|
+
}
|
99
|
+
|
100
|
+
static VALUE point_from_lon_lat(VALUE self, VALUE rb_lon1, VALUE rb_lat1, VALUE rb_bearing, VALUE rb_distance, VALUE rb_a, VALUE rb_b) {
|
101
|
+
Check_Type(rb_lon1, T_FLOAT);
|
102
|
+
Check_Type(rb_lat1, T_FLOAT);
|
103
|
+
Check_Type(rb_bearing, T_FLOAT);
|
104
|
+
Check_Type(rb_distance, T_FLOAT);
|
105
|
+
Check_Type(rb_a, T_FLOAT);
|
106
|
+
Check_Type(rb_b, T_FLOAT);
|
107
|
+
|
108
|
+
VALUE ret;
|
109
|
+
|
110
|
+
double lon1 = RFLOAT(rb_lon1)->value;
|
111
|
+
double lat1 = RFLOAT(rb_lat1)->value;
|
112
|
+
double brng = RFLOAT(rb_bearing)->value;
|
113
|
+
double s = RFLOAT(rb_distance)->value;
|
114
|
+
double a = RFLOAT(rb_a)->value;
|
115
|
+
double b = RFLOAT(rb_b)->value;
|
116
|
+
|
117
|
+
double f = (a-b) / a;
|
118
|
+
double alpha1 = brng * DEG_TO_RAD;
|
119
|
+
double sinAlpha1 = sin(alpha1), cosAlpha1 = cos(alpha1);
|
120
|
+
|
121
|
+
double tanU1 = (1-f) * tan(lat1 * DEG_TO_RAD);
|
122
|
+
double cosU1 = 1 / sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1;
|
123
|
+
double sigma1 = atan2(tanU1, cosAlpha1);
|
124
|
+
double sinAlpha = cosU1 * sinAlpha1;
|
125
|
+
double cosSqAlpha = 1 - sinAlpha*sinAlpha;
|
126
|
+
double uSq = cosSqAlpha * (a*a - b*b) / (b*b);
|
127
|
+
double A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
|
128
|
+
double B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
|
129
|
+
|
130
|
+
double sigma = s / (b*A), sigmaP = 2*PI;
|
131
|
+
double cos2SigmaM, sinSigma, deltaSigma, cosSigma;
|
132
|
+
while (fabs(sigma-sigmaP) > 1e-12) {
|
133
|
+
cos2SigmaM = cos(2*sigma1 + sigma);
|
134
|
+
sinSigma = sin(sigma), cosSigma = cos(sigma);
|
135
|
+
deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
|
136
|
+
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
|
137
|
+
sigmaP = sigma;
|
138
|
+
sigma = s / (b*A) + deltaSigma;
|
139
|
+
}
|
140
|
+
|
141
|
+
double tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1;
|
142
|
+
double lat2 = atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1, (1-f)*sqrt(sinAlpha*sinAlpha + tmp*tmp));
|
143
|
+
double lambda = atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1);
|
144
|
+
double C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
|
145
|
+
double L = lambda - (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
|
146
|
+
|
147
|
+
double revAz = atan2(sinAlpha, -tmp); // final bearing
|
148
|
+
|
149
|
+
ret = rb_ary_new2(2); /* [lon, lat] */
|
150
|
+
rb_ary_store(ret, 0, rb_float_new(lon1+L/DEG_TO_RAD));
|
151
|
+
rb_ary_store(ret, 1, rb_float_new(lat2/DEG_TO_RAD));
|
152
|
+
|
153
|
+
return ret;
|
154
|
+
}
|
155
|
+
|
156
|
+
void Init_grextras()
|
157
|
+
{
|
158
|
+
rb_mVincenty = rb_define_module("Vincenty");
|
159
|
+
rb_define_module_function(rb_mVincenty, "distance", distance, 6);
|
160
|
+
rb_define_module_function(rb_mVincenty, "point_from_lon_lat", point_from_lon_lat, 6);
|
161
|
+
|
162
|
+
rb_mPointInPoly = rb_define_module("PointInPoly");
|
163
|
+
rb_define_module_function(rb_mPointInPoly, "point_in_poly", point_in_poly, 3);
|
164
|
+
}
|
165
|
+
|
166
|
+
// end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'geo_ruby'
|
2
|
+
require "#{File.dirname(__FILE__)}/../ext/grextras"
|
3
|
+
|
4
|
+
module GeoRuby
|
5
|
+
module SimpleFeatures
|
6
|
+
class Point < Geometry
|
7
|
+
|
8
|
+
alias_method :orig_ellipsoidal_distance, :ellipsoidal_distance
|
9
|
+
|
10
|
+
# Implementation of the Vincenty 'distance' formula to find the ellipsoidal distance between points
|
11
|
+
# As per implementation by Chris Veness (http://www.movable-type.co.uk/scripts/latlong-vincenty.html)
|
12
|
+
# Default a/b values are for the WGS84 ellipsoid - other values may be specified
|
13
|
+
def ellipsoidal_distance(point, a = 6378137.0, b = 6356752.3142)
|
14
|
+
Vincenty.distance(x.to_f, y.to_f, point.x.to_f, point.y.to_f, a.to_f, b.to_f)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Implementation of the Vincenty 'direct' formula to find a point based on a bearing and distance
|
18
|
+
# As per implementation by Chris Veness (http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html)
|
19
|
+
# Default a/b values are for the WGS84 ellipsoid - other values may be specified
|
20
|
+
def point_at_bearing_and_distance(bearing=0.0, distance=0.0, a = 6378137.0, b = 6356752.3142)
|
21
|
+
Point.from_coordinates(Vincenty.point_from_lon_lat(lon.to_f,lat.to_f,bearing.to_f,distance.to_f,a.to_f,b.to_f))
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class LinearRing < LineString
|
28
|
+
def fast_contains?(point)
|
29
|
+
!!PointInPoly.point_in_poly(point.x.to_f, point.y.to_f, points)
|
30
|
+
end
|
31
|
+
|
32
|
+
def slow_contains?(point_to_check)
|
33
|
+
c = 0
|
34
|
+
last = points[points.length - 1]
|
35
|
+
|
36
|
+
points.each do |point|
|
37
|
+
if (point.y > point_to_check.y) != (last.y > point_to_check.y)
|
38
|
+
c += 1 if point_to_check.x < (last.x - point.x) * (point_to_check.y - point.y) / (last.y / point.y) + point.x
|
39
|
+
end
|
40
|
+
last = point
|
41
|
+
end
|
42
|
+
((c % 2) == 1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/test/test_pnpoly.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'geo_ruby'
|
5
|
+
require "#{File.dirname(__FILE__)}/../lib/georuby-extras"
|
6
|
+
|
7
|
+
class PointInPolyTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
include GeoRuby::SimpleFeatures
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@poly_points = [[-95.81394, 41.008889], [-95.8103490000001, 41.0089209999999], [-95.8109810000001, 41.0072869999999], [-95.8113760000001, 41.00503], [-95.812187, 41.0017499999999], [-95.818804, 41.0017539999999], [-95.8187930000001, 41.0031709999998], [-95.8186090000002, 41.0038159999999], [-95.8186070000002, 41.008026], [-95.8185370000001, 41.008341], [-95.8183790000001, 41.008529], [-95.8181140000002, 41.008707], [-95.8178770000002, 41.0088039999998], [-95.817137, 41.00881], [-95.8158390000001, 41.0088089999999], [-95.815024, 41.0088289999999], [-95.8146770000001, 41.008836], [-95.8141700000001, 41.0089859999998], [-95.81394, 41.008889]]
|
13
|
+
|
14
|
+
@in_points = [[-95.8169174194336, 41.0077548921441], [-95.8169174194336, 41.0065242578572], [-95.8161449432373, 41.0053259865994], [-95.8147716522217, 41.0043543993136], [-95.8134412765503, 41.0042248532598], [-95.8128833770752, 41.0051316702882], [-95.812668800354, 41.0062327884756], [-95.8130550384521, 41.0073015032386], [-95.8149433135986, 41.0080787394523], [-95.8169174194336, 41.0077548921441], [-95.8176898956299, 41.0056498458448], [-95.8179044723511, 41.0042572397971], [-95.8179044723511, 41.0032856367545], [-95.817174911499, 41.0025731187526], [-95.8152008056641, 41.0024111817688], [-95.8140420913696, 41.0028322170991], [-95.81627368927, 41.0046134906571], [-95.8176898956299, 41.0056498458448], [-95.8176898956299, 41.0056498458448], [-95.8179044723511, 41.0042572397971], [-95.8179044723511, 41.0032856367545], [-95.817174911499, 41.0025731187526], [-95.8152008056641, 41.0024111817688], [-95.8140420913696, 41.0028322170991], [-95.81627368927, 41.0046134906571], [-95.8176898956299, 41.0056498458448], [-95.8176898956299, 41.0056498458448], [-95.8179044723511, 41.0042572397971], [-95.8179044723511, 41.0032856367545], [-95.817174911499, 41.0025731187526], [-95.8152008056641, 41.0024111817688], [-95.8140420913696, 41.0028322170991], [-95.81627368927, 41.0046134906571], [-95.8176898956299, 41.0056498458448]]
|
15
|
+
|
16
|
+
@out_points = [[-95.8193635940552, 41.0129038758068], [-95.8218097686768, 41.0130657870063], [-95.8228826522827, 41.0119000174887], [-95.8237838745117, 41.0105399269802], [-95.8245992660522, 41.0094388807662], [-95.8248996734619, 41.0079168159972], [-95.8250713348389, 41.0057793890973], [-95.8250713348389, 41.0039009870114], [-95.8233976364136, 41.0047430359468], [-95.8213806152344, 41.0071071927528], [-95.8201789855957, 41.0094388807662], [-95.8179903030396, 41.0117057205636], [-95.8126258850098, 41.0110256768135], [-95.808162689209, 41.0107666106814], [-95.8079051971436, 41.0123209921941], [-95.8193635940552, 41.0129038758068], [-95.8236122131348, 41.003091314427], [-95.8249855041504, 41.0019253684299], [-95.8249855041504, 40.9997877471958], [-95.8235263824463, 40.9977796156103], [-95.8193635940552, 40.9971642082001], [-95.8149433135986, 40.9953179514964], [-95.8091926574707, 40.9967431366616], [-95.8089351654053, 41.0000468564923], [-95.8184623718262, 41.0002087992855], [-95.8212089538574, 41.0019253684299], [-95.8236122131348, 41.003091314427], [-95.8074331283569, 41.0099894061731], [-95.8079051971436, 41.0069776521105], [-95.8079051971436, 41.0044839451126], [-95.8078193664551, 41.0022168568629], [-95.8072185516357, 40.9995286368806], [-95.8069610595703, 40.9978120053149], [-95.8051586151123, 40.9979415639739], [-95.8033990859985, 40.9988808566362], [-95.8033990859985, 41.0025731187526], [-95.8074331283569, 41.0099894061731]]
|
17
|
+
|
18
|
+
@ring = LinearRing.from_coordinates(@poly_points)
|
19
|
+
# @polygon = Polygon.from_linear_rings([@ring])
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_in_points
|
23
|
+
@in_points.each_with_index do |coord, i|
|
24
|
+
point = Point.from_coordinates(coord)
|
25
|
+
assert_equal true, @ring.fast_contains?(point), "point with index #{i} should be in the ring"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_out_points
|
30
|
+
@out_points.each_with_index do |coord, i|
|
31
|
+
point = Point.from_coordinates(coord)
|
32
|
+
assert_equal false, @ring.fast_contains?(point), "point with index #{i} should not be in the ring"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'geo_ruby'
|
5
|
+
require "#{File.dirname(__FILE__)}/../lib/georuby-extras"
|
6
|
+
|
7
|
+
class GeoHashNativeTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
include GeoRuby::SimpleFeatures
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@home = Point.from_lon_lat(-76.511,39.024)
|
13
|
+
@nyc = Point.from_lon_lat(-74,40.6)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_distance
|
17
|
+
assert_in_delta 277195.5104, @home.ellipsoidal_distance(@nyc), 0.001
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_orig_distance
|
21
|
+
assert_in_delta 277195.5104, @home.orig_ellipsoidal_distance(@nyc), 0.001
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_bearing_from_point
|
25
|
+
dest = @home.point_at_bearing_and_distance(91.0, 130000.0)
|
26
|
+
assert_in_delta -75.0106, dest.x, 0.0001
|
27
|
+
assert_in_delta 38.9939, dest.y, 0.0001
|
28
|
+
end
|
29
|
+
|
30
|
+
# This test is basically identical to those in georuby; to confirm compatibility
|
31
|
+
def test_point_distance
|
32
|
+
point1 = Point.from_x_y(0,0)
|
33
|
+
point2 = Point.from_x_y(3,4)
|
34
|
+
assert_equal(5,point1.euclidian_distance(point2))
|
35
|
+
|
36
|
+
assert_in_delta(554058.924,point1.ellipsoidal_distance(point2),0.001)
|
37
|
+
assert_in_delta(554058.924,point1.orig_ellipsoidal_distance(point2),0.001)
|
38
|
+
|
39
|
+
assert_in_delta(555811.68,point1.spherical_distance(point2),0.01)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: griffordson-georuby-extras
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 7
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
- 0
|
10
|
+
version: 0.6.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- David Troy
|
14
|
+
- Matt Griffith
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-06-30 00:00:00 -05:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: GeoRuby
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 31
|
31
|
+
segments:
|
32
|
+
- 1
|
33
|
+
- 2
|
34
|
+
- 0
|
35
|
+
version: 1.2.0
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
description: Provides native implementations of Vincenty ellipsoidal functions and a native implementation of a ray casting algorithm to detect if a point is contained in a polygon.
|
39
|
+
email: matt@griffith.com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions:
|
43
|
+
- ext/extconf.rb
|
44
|
+
extra_rdoc_files:
|
45
|
+
- Manifest.txt
|
46
|
+
- README
|
47
|
+
- History.txt
|
48
|
+
files:
|
49
|
+
- ext/extconf.rb
|
50
|
+
- ext/vincenty.c
|
51
|
+
- lib/georuby-extras.rb
|
52
|
+
- ext/pnpoly.c
|
53
|
+
- ext/pnpoly.h
|
54
|
+
- Manifest.txt
|
55
|
+
- README
|
56
|
+
- History.txt
|
57
|
+
- test/test_vincenty.rb
|
58
|
+
- test/test_pnpoly.rb
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://github.com/griffordson/georuby-extras
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- --main
|
66
|
+
- README
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
hash: 3
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.7
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: Native extensions and extra functions for the GeoRuby library.
|
94
|
+
test_files:
|
95
|
+
- test/test_vincenty.rb
|
96
|
+
- test/test_pnpoly.rb
|