georuby 2.3.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +16 -9
- data/Rakefile +13 -14
- data/lib/geo_ruby/ewk.rb +2 -0
- data/lib/geo_ruby/{simple_features → ewk}/ewkb_parser.rb +206 -218
- data/lib/geo_ruby/ewk/ewkt_parser.rb +321 -0
- data/lib/geo_ruby/geojson.rb +27 -32
- data/lib/geo_ruby/georss.rb +88 -66
- data/lib/geo_ruby/gpx.rb +113 -1
- data/lib/geo_ruby/kml.rb +43 -31
- data/lib/geo_ruby/shp.rb +1 -0
- data/lib/geo_ruby/shp4r/dbf.rb +7 -3
- data/lib/geo_ruby/shp4r/shp.rb +297 -284
- data/lib/geo_ruby/simple_features.rb +2 -6
- data/lib/geo_ruby/simple_features/circle.rb +15 -13
- data/lib/geo_ruby/simple_features/envelope.rb +84 -77
- data/lib/geo_ruby/simple_features/geometry.rb +89 -69
- data/lib/geo_ruby/simple_features/geometry_collection.rb +46 -43
- data/lib/geo_ruby/simple_features/geometry_factory.rb +50 -47
- data/lib/geo_ruby/simple_features/helper.rb +14 -14
- data/lib/geo_ruby/simple_features/line_string.rb +94 -97
- data/lib/geo_ruby/simple_features/linear_ring.rb +4 -9
- data/lib/geo_ruby/simple_features/multi_line_string.rb +18 -21
- data/lib/geo_ruby/simple_features/multi_point.rb +18 -20
- data/lib/geo_ruby/simple_features/multi_polygon.rb +19 -25
- data/lib/geo_ruby/simple_features/point.rb +134 -128
- data/lib/geo_ruby/simple_features/polygon.rb +60 -59
- data/lib/geo_ruby/version.rb +1 -1
- data/spec/data/geojson/feature.json +9 -0
- data/spec/data/geojson/feature_collection.json +3 -4
- data/spec/geo_ruby/{simple_features → ewk}/ewkb_parser_spec.rb +56 -57
- data/spec/geo_ruby/{simple_features → ewk}/ewkt_parser_spec.rb +62 -63
- data/spec/geo_ruby/geojson_spec.rb +34 -17
- data/spec/geo_ruby/georss_spec.rb +76 -64
- data/spec/geo_ruby/{gpx4r/gpx_spec.rb → gpx_spec.rb} +25 -25
- data/spec/geo_ruby/kml_spec.rb +40 -36
- data/spec/geo_ruby/shp4r/shp_spec.rb +51 -51
- data/spec/geo_ruby/simple_features/circle_spec.rb +2 -2
- data/spec/geo_ruby/simple_features/envelope_spec.rb +8 -8
- data/spec/geo_ruby/simple_features/geometry_collection_spec.rb +26 -26
- data/spec/geo_ruby/simple_features/geometry_factory_spec.rb +5 -5
- data/spec/geo_ruby/simple_features/geometry_spec.rb +8 -8
- data/spec/geo_ruby/simple_features/line_string_spec.rb +102 -102
- data/spec/geo_ruby/simple_features/linear_ring_spec.rb +7 -7
- data/spec/geo_ruby/simple_features/multi_line_string_spec.rb +20 -20
- data/spec/geo_ruby/simple_features/multi_point_spec.rb +16 -16
- data/spec/geo_ruby/simple_features/multi_polygon_spec.rb +19 -19
- data/spec/geo_ruby/simple_features/point_spec.rb +180 -174
- data/spec/geo_ruby/simple_features/polygon_spec.rb +55 -56
- data/spec/geo_ruby_spec.rb +4 -4
- data/spec/spec_helper.rb +19 -13
- metadata +10 -9
- data/lib/geo_ruby/gpx4r/gpx.rb +0 -118
- data/lib/geo_ruby/simple_features/ewkt_parser.rb +0 -336
@@ -1,15 +1,12 @@
|
|
1
1
|
require 'geo_ruby/simple_features/line_string'
|
2
2
|
|
3
3
|
module GeoRuby
|
4
|
-
|
5
4
|
module SimpleFeatures
|
6
|
-
|
7
|
-
#
|
8
|
-
#Currently, no check is performed to verify if the linear ring is really closed.
|
5
|
+
# Represents a linear ring, which is a closed line string (see LineString).
|
6
|
+
# Currently, no check is performed to verify if the linear ring is really closed.
|
9
7
|
class LinearRing < LineString
|
10
|
-
|
11
|
-
|
12
|
-
super(srid,with_z,with_m)
|
8
|
+
def initialize(srid = DEFAULT_SRID, with_z = false, with_m = false)
|
9
|
+
super(srid, with_z, with_m)
|
13
10
|
end
|
14
11
|
|
15
12
|
# fix kml export
|
@@ -33,7 +30,5 @@ module GeoRuby
|
|
33
30
|
crossings.size % 2 == 1
|
34
31
|
end
|
35
32
|
end
|
36
|
-
|
37
33
|
end
|
38
|
-
|
39
34
|
end
|
@@ -1,13 +1,10 @@
|
|
1
1
|
require 'geo_ruby/simple_features/geometry_collection'
|
2
2
|
|
3
3
|
module GeoRuby
|
4
|
-
|
5
4
|
module SimpleFeatures
|
6
|
-
|
7
|
-
#Represents a group of line strings (see LineString).
|
5
|
+
# Represents a group of line strings (see LineString).
|
8
6
|
class MultiLineString < GeometryCollection
|
9
|
-
|
10
|
-
def initialize(srid = DEFAULT_SRID,with_z=false,with_m=false)
|
7
|
+
def initialize(srid = DEFAULT_SRID, _with_z = false, _with_m = false)
|
11
8
|
super(srid)
|
12
9
|
end
|
13
10
|
|
@@ -19,39 +16,39 @@ module GeoRuby
|
|
19
16
|
geometries.map(&:points).flatten
|
20
17
|
end
|
21
18
|
|
22
|
-
#Text representation of a multi line string
|
23
|
-
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
24
|
-
@geometries.collect{|line_string|
|
19
|
+
# Text representation of a multi line string
|
20
|
+
def text_representation(allow_z = true, allow_m = true) #:nodoc:
|
21
|
+
@geometries.collect { |line_string| '(' + line_string.text_representation(allow_z, allow_m) + ')' }.join(',')
|
25
22
|
end
|
26
23
|
|
27
|
-
#WKT geometry type
|
24
|
+
# WKT geometry type
|
28
25
|
def text_geometry_type #:nodoc:
|
29
|
-
|
26
|
+
'MULTILINESTRING'
|
30
27
|
end
|
31
28
|
|
32
|
-
def to_line_string(
|
29
|
+
def to_line_string(_join = true)
|
33
30
|
LineString.from_points(points)
|
34
31
|
end
|
35
32
|
|
36
33
|
def to_coordinates
|
37
|
-
geometries.map
|
34
|
+
geometries.map(&:to_coordinates)
|
38
35
|
end
|
39
36
|
|
40
|
-
def as_json(
|
41
|
-
{:
|
37
|
+
def as_json(_options = {})
|
38
|
+
{ type: 'MultiLineString', coordinates: to_coordinates }
|
42
39
|
end
|
43
40
|
|
44
|
-
#Creates a new multi line string from an array of line strings
|
45
|
-
def self.from_line_strings(line_strings,srid=DEFAULT_SRID,with_z=false,with_m=false)
|
46
|
-
multi_line_string = new(srid,with_z,with_m)
|
41
|
+
# Creates a new multi line string from an array of line strings
|
42
|
+
def self.from_line_strings(line_strings, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
43
|
+
multi_line_string = new(srid, with_z, with_m)
|
47
44
|
multi_line_string.concat(line_strings)
|
48
45
|
multi_line_string
|
49
46
|
end
|
50
47
|
|
51
|
-
#Creates a new multi line string from sequences of points : (((x,y)...(x,y)),((x,y)...(x,y)))
|
52
|
-
def self.from_coordinates(point_sequences,srid=DEFAULT_SRID,with_z=false,with_m=false)
|
53
|
-
multi_line_string = new(srid,with_z,with_m)
|
54
|
-
multi_line_string.concat(point_sequences.collect {|points| LineString.from_coordinates(points,srid,with_z,with_m) })
|
48
|
+
# Creates a new multi line string from sequences of points : (((x,y)...(x,y)),((x,y)...(x,y)))
|
49
|
+
def self.from_coordinates(point_sequences, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
50
|
+
multi_line_string = new(srid, with_z, with_m)
|
51
|
+
multi_line_string.concat(point_sequences.collect { |points| LineString.from_coordinates(points, srid, with_z, with_m) })
|
55
52
|
multi_line_string
|
56
53
|
end
|
57
54
|
end
|
@@ -2,11 +2,10 @@ require 'geo_ruby/simple_features/geometry_collection'
|
|
2
2
|
|
3
3
|
module GeoRuby
|
4
4
|
module SimpleFeatures
|
5
|
-
#Represents a group of points (see Point).
|
5
|
+
# Represents a group of points (see Point).
|
6
6
|
class MultiPoint < GeometryCollection
|
7
|
-
|
8
|
-
|
9
|
-
super(srid,with_z,with_m)
|
7
|
+
def initialize(srid = DEFAULT_SRID, with_z = false, with_m = false)
|
8
|
+
super(srid, with_z, with_m)
|
10
9
|
end
|
11
10
|
|
12
11
|
def binary_geometry_type #:nodoc:
|
@@ -17,38 +16,37 @@ module GeoRuby
|
|
17
16
|
@geometries
|
18
17
|
end
|
19
18
|
|
20
|
-
#Text representation of a MultiPoint
|
21
|
-
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
22
|
-
|
19
|
+
# Text representation of a MultiPoint
|
20
|
+
def text_representation(allow_z = true, allow_m = true) #:nodoc:
|
21
|
+
'(' + @geometries.collect { |point| point.text_representation(allow_z, allow_m) }.join('),(') + ')'
|
23
22
|
end
|
24
23
|
|
25
|
-
#WKT geoemtry type
|
24
|
+
# WKT geoemtry type
|
26
25
|
def text_geometry_type #:nodoc:
|
27
|
-
|
26
|
+
'MULTIPOINT'
|
28
27
|
end
|
29
28
|
|
30
29
|
def to_coordinates
|
31
|
-
points.map
|
30
|
+
points.map(&:to_coordinates)
|
32
31
|
end
|
33
32
|
|
34
|
-
def as_json(
|
35
|
-
{:
|
33
|
+
def as_json(_options = {})
|
34
|
+
{ type: 'MultiPoint', coordinates: to_coordinates }
|
36
35
|
end
|
37
36
|
|
38
|
-
#Creates a new multi point from an array of points
|
39
|
-
def self.from_points(points,srid= DEFAULT_SRID,with_z=false,with_m=false)
|
40
|
-
multi_point= new(srid,with_z,with_m)
|
37
|
+
# Creates a new multi point from an array of points
|
38
|
+
def self.from_points(points, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
39
|
+
multi_point = new(srid, with_z, with_m)
|
41
40
|
multi_point.concat(points)
|
42
41
|
multi_point
|
43
42
|
end
|
44
43
|
|
45
|
-
#Creates a new multi point from a list of point coordinates : ((x,y)...(x,y))
|
46
|
-
def self.from_coordinates(points,srid= DEFAULT_SRID,with_z=false,with_m=false)
|
47
|
-
multi_point= new(srid,with_z,with_m)
|
48
|
-
multi_point.concat(points.collect {|point| Point.from_coordinates(point,srid,with_z,with_m)})
|
44
|
+
# Creates a new multi point from a list of point coordinates : ((x,y)...(x,y))
|
45
|
+
def self.from_coordinates(points, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
46
|
+
multi_point = new(srid, with_z, with_m)
|
47
|
+
multi_point.concat(points.collect { |point| Point.from_coordinates(point, srid, with_z, with_m) })
|
49
48
|
multi_point
|
50
49
|
end
|
51
|
-
|
52
50
|
end
|
53
51
|
end
|
54
52
|
end
|
@@ -1,13 +1,10 @@
|
|
1
1
|
require 'geo_ruby/simple_features/geometry_collection'
|
2
2
|
|
3
3
|
module GeoRuby
|
4
|
-
|
5
4
|
module SimpleFeatures
|
6
|
-
|
7
|
-
#Represents a group of polygons (see Polygon).
|
5
|
+
# Represents a group of polygons (see Polygon).
|
8
6
|
class MultiPolygon < GeometryCollection
|
9
|
-
|
10
|
-
def initialize(srid = DEFAULT_SRID,with_z=false,with_m=false)
|
7
|
+
def initialize(srid = DEFAULT_SRID, _with_z = false, _with_m = false)
|
11
8
|
super(srid)
|
12
9
|
end
|
13
10
|
|
@@ -16,46 +13,43 @@ module GeoRuby
|
|
16
13
|
end
|
17
14
|
|
18
15
|
def points
|
19
|
-
@points ||= geometries.
|
16
|
+
@points ||= geometries.reduce([]) do |arr, r|
|
20
17
|
arr.concat(r.rings.map(&:points).flatten)
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
#Text representation of a MultiPolygon
|
25
|
-
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
26
|
-
@geometries.map {|polygon|
|
21
|
+
# Text representation of a MultiPolygon
|
22
|
+
def text_representation(allow_z = true, allow_m = true) #:nodoc:
|
23
|
+
@geometries.map { |polygon| '(' + polygon.text_representation(allow_z, allow_m) + ')' }.join(',')
|
27
24
|
end
|
28
25
|
|
29
|
-
#WKT geometry type
|
26
|
+
# WKT geometry type
|
30
27
|
def text_geometry_type #:nodoc:
|
31
|
-
|
28
|
+
'MULTIPOLYGON'
|
32
29
|
end
|
33
30
|
|
34
31
|
def to_coordinates
|
35
|
-
geometries.map
|
32
|
+
geometries.map(&:to_coordinates)
|
36
33
|
end
|
37
34
|
|
38
|
-
def as_json(
|
39
|
-
{:
|
40
|
-
|
35
|
+
def as_json(_options = {})
|
36
|
+
{ type: 'MultiPolygon',
|
37
|
+
coordinates: to_coordinates }
|
41
38
|
end
|
42
39
|
|
43
|
-
#Creates a multi polygon from an array of polygons
|
44
|
-
def self.from_polygons(polygons,srid=DEFAULT_SRID,with_z=false,with_m=false)
|
45
|
-
multi_polygon = new(srid,with_z,with_m)
|
40
|
+
# Creates a multi polygon from an array of polygons
|
41
|
+
def self.from_polygons(polygons, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
42
|
+
multi_polygon = new(srid, with_z, with_m)
|
46
43
|
multi_polygon.concat(polygons)
|
47
44
|
multi_polygon
|
48
45
|
end
|
49
46
|
|
50
|
-
#Creates a multi polygon from sequences of points : ((((x,y)...(x,y)),((x,y)...(x,y)),((x,y)...(x,y)))
|
51
|
-
def self.from_coordinates(point_sequence_sequences,srid= DEFAULT_SRID,with_z=false,with_m=false)
|
52
|
-
multi_polygon = new(srid,with_z,with_m)
|
53
|
-
multi_polygon.concat(
|
47
|
+
# Creates a multi polygon from sequences of points : ((((x,y)...(x,y)),((x,y)...(x,y)),((x,y)...(x,y)))
|
48
|
+
def self.from_coordinates(point_sequence_sequences, srid = DEFAULT_SRID, with_z = false, with_m = false)
|
49
|
+
multi_polygon = new(srid, with_z, with_m)
|
50
|
+
multi_polygon.concat(point_sequence_sequences.collect { |point_sequences| Polygon.from_coordinates(point_sequences, srid, with_z, with_m) })
|
54
51
|
multi_polygon
|
55
52
|
end
|
56
|
-
|
57
53
|
end
|
58
|
-
|
59
54
|
end
|
60
|
-
|
61
55
|
end
|
@@ -7,23 +7,23 @@ module GeoRuby
|
|
7
7
|
class Point < Geometry
|
8
8
|
DEG2RAD = 0.0174532925199433
|
9
9
|
HALFPI = 1.5707963267948966
|
10
|
-
attr_accessor :x
|
10
|
+
attr_accessor :x, :y, :z, :m
|
11
11
|
attr_reader :r, :t # radium and theta
|
12
12
|
|
13
13
|
# If you prefer calling the coordinates lat and lon
|
14
14
|
# (or lng, for GeoKit compatibility)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
alias_method :lon, :x
|
16
|
+
alias_method :lng, :x
|
17
|
+
alias_method :lat, :y
|
18
|
+
alias_method :rad, :r
|
19
|
+
alias_method :tet, :t
|
20
|
+
alias_method :tetha, :t
|
21
21
|
|
22
22
|
def initialize(srid = DEFAULT_SRID, with_z = false, with_m = false)
|
23
23
|
super(srid, with_z, with_m)
|
24
24
|
@x = @y = 0.0
|
25
|
-
@z = 0.0 #default value : meaningful if with_z
|
26
|
-
@m = 0.0 #default value : meaningful if with_m
|
25
|
+
@z = 0.0 # default value : meaningful if with_z
|
26
|
+
@m = 0.0 # default value : meaningful if with_m
|
27
27
|
end
|
28
28
|
|
29
29
|
# Sets all coordinates in one call.
|
@@ -34,7 +34,7 @@ module GeoRuby
|
|
34
34
|
@z = z && !z.is_a?(Numeric) ? z.to_f : z
|
35
35
|
self
|
36
36
|
end
|
37
|
-
|
37
|
+
alias_method :set_lon_lat_z, :set_x_y_z
|
38
38
|
|
39
39
|
# Sets all coordinates of a 2D point in one call
|
40
40
|
def set_x_y(x, y)
|
@@ -42,7 +42,7 @@ module GeoRuby
|
|
42
42
|
@y = y && !y.is_a?(Numeric) ? y.to_f : y
|
43
43
|
self
|
44
44
|
end
|
45
|
-
|
45
|
+
alias_method :set_lon_lat, :set_x_y
|
46
46
|
|
47
47
|
# Return the distance between the 2D points (ie taking care only
|
48
48
|
# of the x and y coordinates), assuming the points are in
|
@@ -58,72 +58,79 @@ module GeoRuby
|
|
58
58
|
# Assumes x is the lon and y the lat, in degrees.
|
59
59
|
# The user has to make sure using this distance makes sense
|
60
60
|
# (ie she should be in latlon coordinates)
|
61
|
-
def spherical_distance(point, r =
|
61
|
+
def spherical_distance(point, r = 6_370_997.0)
|
62
62
|
dlat = (point.lat - lat) * DEG2RAD / 2
|
63
63
|
dlon = (point.lon - lon) * DEG2RAD / 2
|
64
64
|
|
65
65
|
a = Math.sin(dlat)**2 + Math.cos(lat * DEG2RAD) *
|
66
|
-
|
67
|
-
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
|
66
|
+
Math.cos(point.lat * DEG2RAD) * Math.sin(dlon)**2
|
67
|
+
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
68
68
|
r * c
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
71
|
+
#
|
72
|
+
# Ellipsoidal distance in m using Vincenty's formula.
|
73
|
+
# Lifted entirely from Chris Veness's code at
|
74
|
+
# http://www.movable-type.co.uk/scripts/LatLongVincenty.html
|
75
|
+
# and adapted for Ruby.
|
76
|
+
#
|
77
|
+
# Assumes the x and y are the lon and lat in degrees.
|
72
78
|
# a is the semi-major axis (equatorial radius) of the ellipsoid
|
73
79
|
# b is the semi-minor axis (polar radius) of the ellipsoid
|
74
|
-
# Their values by default are set to the
|
75
|
-
|
80
|
+
# Their values by default are set to the WGS84 ellipsoid.
|
81
|
+
#
|
82
|
+
def ellipsoidal_distance(point, a = 6_378_137.0, b = 6_356_752.3142)
|
76
83
|
f = (a - b) / a
|
77
84
|
l = (point.lon - lon) * DEG2RAD
|
78
85
|
|
79
|
-
u1 = Math.atan((1-f) * Math.tan(lat * DEG2RAD
|
80
|
-
u2 = Math.atan((1-f) * Math.tan(point.lat * DEG2RAD))
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
86
|
+
u1 = Math.atan((1 - f) * Math.tan(lat * DEG2RAD))
|
87
|
+
u2 = Math.atan((1 - f) * Math.tan(point.lat * DEG2RAD))
|
88
|
+
sin_u1 = Math.sin(u1)
|
89
|
+
cos_u1 = Math.cos(u1)
|
90
|
+
sin_u2 = Math.sin(u2)
|
91
|
+
cos_u2 = Math.cos(u2)
|
85
92
|
|
86
93
|
lambda = l
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
while (lambda -
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
Math.sqrt((
|
95
|
-
(
|
96
|
-
(
|
97
|
-
|
98
|
-
return 0 if
|
99
|
-
|
100
|
-
|
101
|
-
sigma = Math.atan2(
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
# equatorial line:
|
107
|
-
|
108
|
-
|
109
|
-
c = f / 16 *
|
110
|
-
|
111
|
-
lambda = l + (1 - c) * f *
|
112
|
-
(
|
113
|
-
|
94
|
+
lambda_p = 2 * Math::PI
|
95
|
+
iter_limit = 20
|
96
|
+
|
97
|
+
while (lambda - lambda_p).abs > 1e-12 && --iter_limit > 0
|
98
|
+
sin_lambda = Math.sin(lambda)
|
99
|
+
cos_lambda = Math.cos(lambda)
|
100
|
+
sin_sigma = \
|
101
|
+
Math.sqrt((cos_u2 * sin_lambda) * (cos_u2 * sin_lambda) +
|
102
|
+
(cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda) *
|
103
|
+
(cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda))
|
104
|
+
|
105
|
+
return 0 if sin_sigma == 0 # coincident points
|
106
|
+
|
107
|
+
cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda
|
108
|
+
sigma = Math.atan2(sin_sigma, cos_sigma)
|
109
|
+
sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin_sigma
|
110
|
+
cos_sq_alpha = 1 - sin_alpha * sin_alpha
|
111
|
+
cos2_sigma_m = cos_sigma - 2 * sin_u1 * sin_u2 / cos_sq_alpha
|
112
|
+
|
113
|
+
# equatorial line: cos_sq_alpha=0
|
114
|
+
cos2_sigma_m = 0 if cos2_sigma_m.nan?
|
115
|
+
|
116
|
+
c = f / 16 * cos_sq_alpha * (4 + f * (4 - 3 * cos_sq_alpha))
|
117
|
+
lambda_p = lambda
|
118
|
+
lambda = l + (1 - c) * f * sin_alpha * (sigma + c * sin_sigma *
|
119
|
+
(cos2_sigma_m + c * cos_sigma * (-1 + 2 * cos2_sigma_m *
|
120
|
+
cos2_sigma_m)))
|
114
121
|
end
|
115
122
|
|
116
|
-
return NaN if
|
123
|
+
return NaN if iter_limit == 0 # formula failed to converge
|
117
124
|
|
118
|
-
|
119
|
-
a_bis = 1 +
|
120
|
-
b_bis =
|
121
|
-
|
122
|
-
(
|
123
|
-
|
124
|
-
|
125
|
+
usq = cos_sq_alpha * (a * a - b * b) / (b * b)
|
126
|
+
a_bis = 1 + usq / 16_384 * (4096 + usq * (-768 + usq * (320 - 175 * usq)))
|
127
|
+
b_bis = usq / 1024 * (256 + usq * (-128 + usq * (74 - 47 * usq)))
|
128
|
+
delta_sigma = b_bis * sin_sigma * (cos2_sigma_m + b_bis / 4 *
|
129
|
+
(cos_sigma * (-1 + 2 * cos2_sigma_m * cos2_sigma_m) - b_bis / 6 *
|
130
|
+
cos2_sigma_m * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 *
|
131
|
+
cos2_sigma_m * cos2_sigma_m)))
|
125
132
|
|
126
|
-
b * a_bis * (sigma -
|
133
|
+
b * a_bis * (sigma - delta_sigma)
|
127
134
|
end
|
128
135
|
|
129
136
|
# Orthogonal Distance
|
@@ -138,7 +145,7 @@ module GeoRuby
|
|
138
145
|
return 0.0 if len.zero?
|
139
146
|
res = dot / len
|
140
147
|
|
141
|
-
xx, yy
|
148
|
+
xx, yy = \
|
142
149
|
if res < 0
|
143
150
|
[head.x, head.y]
|
144
151
|
elsif res > 1
|
@@ -146,16 +153,16 @@ module GeoRuby
|
|
146
153
|
else
|
147
154
|
[head.x + res * c, head.y + res * d]
|
148
155
|
end
|
149
|
-
#
|
156
|
+
# TODO: benchmark if worth creating an instance
|
150
157
|
# euclidian_distance(Point.from_x_y(xx, yy))
|
151
|
-
Math.sqrt((@x - xx)
|
158
|
+
Math.sqrt((@x - xx)**2 + (@y - yy)**2)
|
152
159
|
end
|
153
160
|
|
154
161
|
# Bearing from a point to another, in degrees.
|
155
162
|
def bearing_to(other)
|
156
163
|
return 0 if self == other
|
157
|
-
a,b = other.x -
|
158
|
-
res = Math.acos(b / Math.sqrt(a*a+b*b)) / Math::PI * 180
|
164
|
+
a, b = other.x - x, other.y - y
|
165
|
+
res = Math.acos(b / Math.sqrt(a * a + b * b)) / Math::PI * 180
|
159
166
|
a < 0 ? 360 - res : res
|
160
167
|
end
|
161
168
|
|
@@ -178,37 +185,38 @@ module GeoRuby
|
|
178
185
|
# Bounding box in 2D/3D. Returns an array of 2 points
|
179
186
|
def bounding_box
|
180
187
|
if with_z
|
181
|
-
[Point.from_x_y_z(@x
|
188
|
+
[Point.from_x_y_z(@x, @y, @z), Point.from_x_y_z(@x, @y, @z)]
|
182
189
|
else
|
183
|
-
[Point.from_x_y(@x
|
190
|
+
[Point.from_x_y(@x, @y), Point.from_x_y(@x, @y)]
|
184
191
|
end
|
185
192
|
end
|
186
193
|
|
187
194
|
def m_range
|
188
|
-
[@m
|
195
|
+
[@m, @m]
|
189
196
|
end
|
190
197
|
|
191
198
|
# Tests the equality of the position of points + m
|
192
199
|
def ==(other)
|
193
|
-
return false unless other.
|
200
|
+
return false unless other.is_a?(Point)
|
194
201
|
@x == other.x && @y == other.y && @z == other.z && @m == other.m
|
195
202
|
end
|
196
203
|
|
197
|
-
# Binary representation of a point.
|
198
|
-
|
199
|
-
|
200
|
-
bin_rep
|
201
|
-
bin_rep += [@
|
204
|
+
# Binary representation of a point.
|
205
|
+
# It lacks some headers to be a valid EWKB representation.
|
206
|
+
def binary_representation(allow_z = true, allow_m = true) #:nodoc:
|
207
|
+
bin_rep = [@x.to_f, @y.to_f].pack('EE')
|
208
|
+
bin_rep += [@z.to_f].pack('E') if @with_z && allow_z # Default value so no crash
|
209
|
+
bin_rep += [@m.to_f].pack('E') if @with_m && allow_m # idem
|
202
210
|
bin_rep
|
203
211
|
end
|
204
212
|
|
205
213
|
# WKB geometry type of a point
|
206
|
-
def binary_geometry_type#:nodoc:
|
214
|
+
def binary_geometry_type #:nodoc:
|
207
215
|
1
|
208
216
|
end
|
209
217
|
|
210
218
|
# Text representation of a point
|
211
|
-
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
219
|
+
def text_representation(allow_z = true, allow_m = true) #:nodoc:
|
212
220
|
tex_rep = "#{@x} #{@y}"
|
213
221
|
tex_rep += " #{@z}" if @with_z && allow_z
|
214
222
|
tex_rep += " #{@m}" if @with_m && allow_m
|
@@ -222,24 +230,23 @@ module GeoRuby
|
|
222
230
|
|
223
231
|
# georss simple representation
|
224
232
|
def georss_simple_representation(options) #:nodoc:
|
225
|
-
georss_ns = options[:georss_ns] ||
|
233
|
+
georss_ns = options[:georss_ns] || 'georss'
|
226
234
|
geom_attr = options[:geom_attr]
|
227
235
|
"<#{georss_ns}:point#{geom_attr}>#{y} #{x}</#{georss_ns}:point>\n"
|
228
236
|
end
|
229
237
|
|
230
238
|
# georss w3c representation
|
231
239
|
def georss_w3cgeo_representation(options) #:nodoc:
|
232
|
-
w3cgeo_ns = options[:w3cgeo_ns] ||
|
240
|
+
w3cgeo_ns = options[:w3cgeo_ns] || 'geo'
|
233
241
|
"<#{w3cgeo_ns}:lat>#{y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{x}</#{w3cgeo_ns}:long>\n"
|
234
242
|
end
|
235
243
|
|
236
244
|
# georss gml representation
|
237
245
|
def georss_gml_representation(options) #:nodoc:
|
238
|
-
georss_ns = options[:georss_ns] ||
|
239
|
-
gml_ns = options[:gml_ns] ||
|
240
|
-
|
241
|
-
|
242
|
-
out += "</#{gml_ns}:pos>\n</#{gml_ns}:Point>\n</#{georss_ns}:where>\n"
|
246
|
+
georss_ns = options[:georss_ns] || 'georss'
|
247
|
+
gml_ns = options[:gml_ns] || 'gml'
|
248
|
+
"<#{georss_ns}:where>\n<#{gml_ns}:Point>\n<#{gml_ns}:pos>#{y} #{x}" \
|
249
|
+
"</#{gml_ns}:pos>\n</#{gml_ns}:Point>\n</#{georss_ns}:where>\n"
|
243
250
|
end
|
244
251
|
|
245
252
|
# outputs the geometry in kml format : options are
|
@@ -252,9 +259,9 @@ module GeoRuby
|
|
252
259
|
out = "<Point#{options[:id_attr]}>\n"
|
253
260
|
out += options[:geom_data] if options[:geom_data]
|
254
261
|
out += "<coordinates>#{x},#{y}"
|
255
|
-
out += ",#{options[:fixed_z] || z ||0}" if options[:allow_z]
|
262
|
+
out += ",#{options[:fixed_z] || z || 0}" if options[:allow_z]
|
256
263
|
out += "</coordinates>\n"
|
257
|
-
out
|
264
|
+
out + "</Point>\n"
|
258
265
|
end
|
259
266
|
|
260
267
|
def html_representation(options = {})
|
@@ -262,23 +269,25 @@ module GeoRuby
|
|
262
269
|
out = '<span class=\'geo\'>'
|
263
270
|
out += "<abbr class='latitude' title='#{x}'>#{as_lat(options)}</abbr>"
|
264
271
|
out += "<abbr class='longitude' title='#{y}'>#{as_long(options)}</abbr>"
|
265
|
-
out
|
272
|
+
out + '</span>'
|
266
273
|
end
|
267
274
|
|
268
275
|
# Human representation of the geom, don't use directly, use:
|
269
276
|
# #as_lat, #as_long, #as_latlong
|
270
|
-
def human_representation(options = {
|
277
|
+
def human_representation(options = {}, g = { x: x, y: y })
|
271
278
|
g.map do |k, v|
|
272
279
|
deg = v.to_i.abs
|
273
280
|
min = (60 * (v.abs - deg)).to_i
|
274
281
|
labs = (v * 1_000_000).abs / 1_000_000
|
275
|
-
sec = ((((labs - labs.to_i) * 60) -
|
276
|
-
|
282
|
+
sec = ((((labs - labs.to_i) * 60) -
|
283
|
+
((labs - labs.to_i) * 60).to_i) * 100_000) * 60 / 100_000
|
284
|
+
str = options[:full] ? '%.i°%.2i′%05.2f″' : '%.i°%.2i′%02.0f″'
|
277
285
|
if options[:coord]
|
278
|
-
out = str
|
279
|
-
|
286
|
+
out = format(str, deg, min, sec)
|
287
|
+
# Add cardinal
|
288
|
+
out + (k == :x ? v > 0 ? 'N' : 'S' : v > 0 ? 'E' : 'W')
|
280
289
|
else
|
281
|
-
str
|
290
|
+
format(str, v.to_i, min, sec)
|
282
291
|
end
|
283
292
|
end
|
284
293
|
end
|
@@ -286,22 +295,22 @@ module GeoRuby
|
|
286
295
|
# Outputs the geometry coordinate in human format:
|
287
296
|
# 47°52′48″N
|
288
297
|
def as_lat(options = {})
|
289
|
-
human_representation(options,
|
298
|
+
human_representation(options, x: x).join
|
290
299
|
end
|
291
300
|
|
292
301
|
# Outputs the geometry coordinate in human format:
|
293
302
|
# -20°06′00W″
|
294
303
|
def as_long(options = {})
|
295
|
-
human_representation(options,
|
304
|
+
human_representation(options, y: y).join
|
296
305
|
end
|
297
|
-
|
306
|
+
alias_method :as_lng, :as_long
|
298
307
|
|
299
308
|
# Outputs the geometry in coordinates format:
|
300
309
|
# 47°52′48″, -20°06′00″
|
301
310
|
def as_latlong(options = {})
|
302
311
|
human_representation(options).join(', ')
|
303
312
|
end
|
304
|
-
|
313
|
+
alias_method :as_ll, :as_latlong
|
305
314
|
|
306
315
|
# Polar stuff
|
307
316
|
#
|
@@ -317,8 +326,8 @@ module GeoRuby
|
|
317
326
|
if @x.zero?
|
318
327
|
@y < 0 ? 3 * HALFPI : HALFPI
|
319
328
|
else
|
320
|
-
th = Math.atan(@y
|
321
|
-
th
|
329
|
+
th = Math.atan(@y / @x)
|
330
|
+
r > 0 ? th + 2 * Math::PI : th
|
322
331
|
end
|
323
332
|
end
|
324
333
|
|
@@ -333,8 +342,8 @@ module GeoRuby
|
|
333
342
|
end
|
334
343
|
|
335
344
|
# Outputs the point in json format
|
336
|
-
def as_json(
|
337
|
-
{:
|
345
|
+
def as_json(_options = {})
|
346
|
+
{ type: 'Point', coordinates: to_coordinates }
|
338
347
|
end
|
339
348
|
|
340
349
|
# Invert signal of all coordinates
|
@@ -342,13 +351,12 @@ module GeoRuby
|
|
342
351
|
set_x_y_z(-@x, -@y, -@z)
|
343
352
|
end
|
344
353
|
|
345
|
-
#
|
354
|
+
# Helper to get all coordinates as array.
|
346
355
|
def to_coordinates
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
end
|
356
|
+
coord = [x, y]
|
357
|
+
coord << z if with_z
|
358
|
+
coord << m if with_m
|
359
|
+
coord
|
352
360
|
end
|
353
361
|
|
354
362
|
# Simple helper for 2D maps
|
@@ -362,12 +370,12 @@ module GeoRuby
|
|
362
370
|
end
|
363
371
|
|
364
372
|
# Creates a point from an array of coordinates
|
365
|
-
def self.from_coordinates(coords, srid = DEFAULT_SRID,
|
366
|
-
if !
|
373
|
+
def self.from_coordinates(coords, srid = DEFAULT_SRID, z = false, m = false)
|
374
|
+
if !(z || m)
|
367
375
|
from_x_y(coords[0], coords[1], srid)
|
368
|
-
elsif
|
376
|
+
elsif z && m
|
369
377
|
from_x_y_z_m(coords[0], coords[1], coords[2], coords[3], srid)
|
370
|
-
elsif
|
378
|
+
elsif z
|
371
379
|
from_x_y_z(coords[0], coords[1], coords[2], srid)
|
372
380
|
else
|
373
381
|
from_x_y_m(coords[0], coords[1], coords[2], srid)
|
@@ -413,7 +421,8 @@ module GeoRuby
|
|
413
421
|
# Creates a point using coordinates like 22`34 23.45N
|
414
422
|
def self.from_latlong(lat, lon, srid = DEFAULT_SRID)
|
415
423
|
p = [lat, lon].map do |l|
|
416
|
-
sig, deg, min, sec, cen =
|
424
|
+
sig, deg, min, sec, cen = \
|
425
|
+
l.scan(/(-)?(\d{1,2})\D*(\d{2})\D*(\d{2})(\D*(\d{1,3}))?/).flatten
|
417
426
|
sig = true if l =~ /W|S/
|
418
427
|
dec = deg.to_i + (min.to_i * 60 + "#{sec}#{cen}".to_f) / 3600
|
419
428
|
sig ? dec * -1 : dec
|
@@ -422,22 +431,19 @@ module GeoRuby
|
|
422
431
|
point.set_x_y(p[0], p[1])
|
423
432
|
end
|
424
433
|
|
425
|
-
# Aliasing the constructors in case you like lat/lon
|
434
|
+
# Aliasing the constructors in case you like lat/lon over y/x
|
426
435
|
class << self
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
end
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
end #SimpleFeatures
|
442
|
-
|
443
|
-
end #GeoRuby
|
436
|
+
alias_method :xy, :from_x_y
|
437
|
+
alias_method :from_xy, :from_x_y
|
438
|
+
alias_method :xyz, :from_x_y_z
|
439
|
+
alias_method :from_xyz, :from_x_y_z
|
440
|
+
alias_method :from_lon_lat_z, :from_x_y_z
|
441
|
+
alias_method :from_lon_lat, :from_x_y
|
442
|
+
alias_method :from_lon_lat_z, :from_x_y_z
|
443
|
+
alias_method :from_lon_lat_m, :from_x_y_m
|
444
|
+
alias_method :from_lon_lat_z_m, :from_x_y_z_m
|
445
|
+
alias_method :from_rad_tet, :from_r_t
|
446
|
+
end
|
447
|
+
end # Point
|
448
|
+
end # SimpleFeatures
|
449
|
+
end # GeoRuby
|