nofxx-georuby 1.3.7
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.
- data/History.txt +4 -0
- data/LICENSE +21 -0
- data/README.txt +59 -0
- data/Rakefile +49 -0
- data/VERSION.yml +4 -0
- data/lib/geo_ruby.rb +21 -0
- data/lib/geo_ruby/base/envelope.rb +167 -0
- data/lib/geo_ruby/base/ewkb_parser.rb +216 -0
- data/lib/geo_ruby/base/ewkt_parser.rb +336 -0
- data/lib/geo_ruby/base/geometry.rb +234 -0
- data/lib/geo_ruby/base/geometry_collection.rb +136 -0
- data/lib/geo_ruby/base/geometry_factory.rb +81 -0
- data/lib/geo_ruby/base/georss_parser.rb +135 -0
- data/lib/geo_ruby/base/helper.rb +18 -0
- data/lib/geo_ruby/base/line_string.rb +184 -0
- data/lib/geo_ruby/base/linear_ring.rb +12 -0
- data/lib/geo_ruby/base/multi_line_string.rb +39 -0
- data/lib/geo_ruby/base/multi_point.rb +41 -0
- data/lib/geo_ruby/base/multi_polygon.rb +37 -0
- data/lib/geo_ruby/base/point.rb +310 -0
- data/lib/geo_ruby/base/polygon.rb +150 -0
- data/lib/geo_ruby/shp4r/dbf.rb +180 -0
- data/lib/geo_ruby/shp4r/shp.rb +701 -0
- data/spec/data/multipoint.dbf +0 -0
- data/spec/data/multipoint.shp +0 -0
- data/spec/data/multipoint.shx +0 -0
- data/spec/data/point.dbf +0 -0
- data/spec/data/point.shp +0 -0
- data/spec/data/point.shx +0 -0
- data/spec/data/polygon.dbf +0 -0
- data/spec/data/polygon.shp +0 -0
- data/spec/data/polygon.shx +0 -0
- data/spec/data/polyline.dbf +0 -0
- data/spec/data/polyline.shp +0 -0
- data/spec/data/polyline.shx +0 -0
- data/spec/geo_ruby/base/envelope_spec.rb +45 -0
- data/spec/geo_ruby/base/ewkb_parser_spec.rb +158 -0
- data/spec/geo_ruby/base/ewkt_parser_spec.rb +179 -0
- data/spec/geo_ruby/base/geometry_collection_spec.rb +55 -0
- data/spec/geo_ruby/base/geometry_factory_spec.rb +11 -0
- data/spec/geo_ruby/base/geometry_spec.rb +32 -0
- data/spec/geo_ruby/base/georss_parser_spec.rb +218 -0
- data/spec/geo_ruby/base/line_string_spec.rb +208 -0
- data/spec/geo_ruby/base/linear_ring_spec.rb +14 -0
- data/spec/geo_ruby/base/multi_line_string_spec.rb +35 -0
- data/spec/geo_ruby/base/multi_point_spec.rb +29 -0
- data/spec/geo_ruby/base/multi_polygon_spec.rb +35 -0
- data/spec/geo_ruby/base/point_spec.rb +275 -0
- data/spec/geo_ruby/base/polygon_spec.rb +108 -0
- data/spec/geo_ruby/shp4r/shp_spec.rb +238 -0
- data/spec/geo_ruby_spec.rb +27 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +12 -0
- metadata +123 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'geo_ruby/base/geometry'
|
2
|
+
|
3
|
+
module GeoRuby
|
4
|
+
module Base
|
5
|
+
#Represents a collection of arbitrary geometries
|
6
|
+
class GeometryCollection < Geometry
|
7
|
+
attr_reader :geometries
|
8
|
+
|
9
|
+
def initialize(srid = @@default_srid,with_z=false,with_m=false)
|
10
|
+
super(srid,with_z,with_m)
|
11
|
+
@geometries = []
|
12
|
+
end
|
13
|
+
|
14
|
+
#Delegate the unknown methods to the geometries array
|
15
|
+
def method_missing(method_name,*args,&b)
|
16
|
+
@geometries.send(method_name,*args,&b)
|
17
|
+
end
|
18
|
+
|
19
|
+
#Bounding box in 2D/3D. Returns an array of 2 points
|
20
|
+
def bounding_box
|
21
|
+
max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
|
22
|
+
if with_z
|
23
|
+
max_z, min_z = -Float::MAX, Float::MAX
|
24
|
+
each do |geometry|
|
25
|
+
bbox = geometry.bounding_box
|
26
|
+
sw = bbox[0]
|
27
|
+
ne = bbox[1]
|
28
|
+
|
29
|
+
max_y = ne.y if ne.y > max_y
|
30
|
+
min_y = sw.y if sw.y < min_y
|
31
|
+
max_x = ne.x if ne.x > max_x
|
32
|
+
min_x = sw.x if sw.x < min_x
|
33
|
+
max_z = ne.z if ne.z > max_z
|
34
|
+
min_z = sw.z if sw.z < min_z
|
35
|
+
end
|
36
|
+
[Point.from_x_y_z(min_x,min_y,min_z),Point.from_x_y_z(max_x,max_y,max_z)]
|
37
|
+
else
|
38
|
+
each do |geometry|
|
39
|
+
bbox = geometry.bounding_box
|
40
|
+
sw = bbox[0]
|
41
|
+
ne = bbox[1]
|
42
|
+
|
43
|
+
max_y = ne.y if ne.y > max_y
|
44
|
+
min_y = sw.y if sw.y < min_y
|
45
|
+
max_x = ne.x if ne.x > max_x
|
46
|
+
min_x = sw.x if sw.x < min_x
|
47
|
+
end
|
48
|
+
[Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def m_range
|
53
|
+
if with_m
|
54
|
+
max_m, min_m = -Float::MAX, Float::MAX
|
55
|
+
each do |lr|
|
56
|
+
lrmr = lr.m_range
|
57
|
+
max_m = lrmr[1] if lrmr[1] > max_m
|
58
|
+
min_m = lrmr[0] if lrmr[0] < min_m
|
59
|
+
end
|
60
|
+
[min_m,max_m]
|
61
|
+
else
|
62
|
+
[0,0]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#tests the equality of geometry collections
|
67
|
+
def ==(other_collection)
|
68
|
+
if(other_collection.class != self.class)
|
69
|
+
false
|
70
|
+
elsif length != other_collection.length
|
71
|
+
false
|
72
|
+
else
|
73
|
+
index=0
|
74
|
+
while index<length
|
75
|
+
return false if self[index] != other_collection[index]
|
76
|
+
index+=1
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#Binary representation of the collection
|
83
|
+
def binary_representation(allow_z=true,allow_m=true) #:nodoc:
|
84
|
+
rep = [length].pack("V")
|
85
|
+
#output the list of geometries without outputting the SRID first and with the same setting regarding Z and M
|
86
|
+
each {|geometry| rep << geometry.as_ewkb(false,allow_z,allow_m) }
|
87
|
+
rep
|
88
|
+
end
|
89
|
+
|
90
|
+
#WKB geometry type of the collection
|
91
|
+
def binary_geometry_type #:nodoc:
|
92
|
+
7
|
93
|
+
end
|
94
|
+
|
95
|
+
#Text representation of a geometry collection
|
96
|
+
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
97
|
+
@geometries.collect{|geometry| geometry.as_ewkt(false,allow_z,allow_m)}.join(",")
|
98
|
+
end
|
99
|
+
|
100
|
+
#WKT geometry type
|
101
|
+
def text_geometry_type #:nodoc:
|
102
|
+
"GEOMETRYCOLLECTION"
|
103
|
+
end
|
104
|
+
|
105
|
+
#georss simple representation : outputs only the first geometry of the collection
|
106
|
+
def georss_simple_representation(options)#:nodoc:
|
107
|
+
self[0].georss_simple_representation(options)
|
108
|
+
end
|
109
|
+
#georss w3c representation : outputs the first point of the outer ring
|
110
|
+
def georss_w3cgeo_representation(options)#:nodoc:
|
111
|
+
self[0].georss_w3cgeo_representation(options)
|
112
|
+
end
|
113
|
+
#georss gml representation : outputs only the first geometry of the collection
|
114
|
+
def georss_gml_representation(options)#:nodoc:
|
115
|
+
self[0].georss_gml_representation(options)
|
116
|
+
end
|
117
|
+
|
118
|
+
#outputs the geometry in kml format
|
119
|
+
def kml_representation(options = {}) #:nodoc:
|
120
|
+
result = "<MultiGeometry#{options[:id_attr]}>\n"
|
121
|
+
options[:id_attr] = "" #the subgeometries do not have an ID
|
122
|
+
each do |geometry|
|
123
|
+
result += geometry.kml_representation(options)
|
124
|
+
end
|
125
|
+
result += "</MultiGeometry>\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
#creates a new GeometryCollection from an array of geometries
|
129
|
+
def self.from_geometries(geometries,srid=@@default_srid,with_z=false,with_m=false)
|
130
|
+
geometry_collection = new(srid,with_z,with_m)
|
131
|
+
geometry_collection.concat(geometries)
|
132
|
+
geometry_collection
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'geo_ruby/base/point'
|
2
|
+
require 'geo_ruby/base/line_string'
|
3
|
+
require 'geo_ruby/base/linear_ring'
|
4
|
+
require 'geo_ruby/base/polygon'
|
5
|
+
require 'geo_ruby/base/multi_point'
|
6
|
+
require 'geo_ruby/base/multi_line_string'
|
7
|
+
require 'geo_ruby/base/multi_polygon'
|
8
|
+
require 'geo_ruby/base/geometry_collection'
|
9
|
+
|
10
|
+
|
11
|
+
module GeoRuby
|
12
|
+
module Base
|
13
|
+
#Creates a new geometry according to constructions received from a parser, for example EWKBParser.
|
14
|
+
class GeometryFactory
|
15
|
+
#the built geometry
|
16
|
+
attr_reader :geometry
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@geometry = nil
|
20
|
+
@geometry_stack = []
|
21
|
+
end
|
22
|
+
#resets the factory
|
23
|
+
def reset
|
24
|
+
@geometry = nil
|
25
|
+
@geometry_stack = []
|
26
|
+
end
|
27
|
+
#add a 2D point to the current geometry
|
28
|
+
def add_point_x_y(x,y)
|
29
|
+
@geometry_stack.last.set_x_y(x,y)
|
30
|
+
end
|
31
|
+
#add 2D points to the current geometry
|
32
|
+
def add_points_x_y(xy)
|
33
|
+
xy.each_slice(2) {|slice| add_point_x_y(*slice)}
|
34
|
+
end
|
35
|
+
#add a 3D point to the current geometry
|
36
|
+
def add_point_x_y_z(x,y,z)
|
37
|
+
@geometry_stack.last.set_x_y_z(x,y,z)
|
38
|
+
end
|
39
|
+
#add 3D points to the current geometry
|
40
|
+
def add_points_x_y_z(xyz)
|
41
|
+
xyz.each_slice(3) {|slice| add_point_x_y_z(*slice)}
|
42
|
+
end
|
43
|
+
#add a 2D point with M to the current geometry
|
44
|
+
def add_point_x_y_m(x,y,m)
|
45
|
+
@geometry_stack.last.set_x_y(x,y)
|
46
|
+
@geometry_stack.last.m=m
|
47
|
+
end
|
48
|
+
#add 2D points with M to the current geometry
|
49
|
+
def add_points_x_y_m(xym)
|
50
|
+
xym.each_slice(3) {|slice| add_point_x_y_m(*slice)}
|
51
|
+
end
|
52
|
+
#add a 3D point with M to the current geometry
|
53
|
+
def add_point_x_y_z_m(x,y,z,m)
|
54
|
+
@geometry_stack.last.set_x_y_z(x,y,z)
|
55
|
+
@geometry_stack.last.m=m
|
56
|
+
end
|
57
|
+
#add 3D points with M to the current geometry
|
58
|
+
def add_points_x_y_z_m(xyzm)
|
59
|
+
xyzm.each_slice(4) {|slice| add_point_x_y_z_m(*slice)}
|
60
|
+
end
|
61
|
+
#begin a geometry of type +geometry_type+
|
62
|
+
def begin_geometry(geometry_type,srid=@@default_srid)
|
63
|
+
geometry= geometry_type::new(srid)
|
64
|
+
@geometry= geometry if @geometry.nil?
|
65
|
+
@geometry_stack << geometry
|
66
|
+
end
|
67
|
+
#terminates the current geometry
|
68
|
+
def end_geometry(with_z=false,with_m=false)
|
69
|
+
@geometry=@geometry_stack.pop
|
70
|
+
@geometry.with_z=with_z
|
71
|
+
@geometry.with_m=with_m
|
72
|
+
#add the newly defined geometry to its parent if there is one
|
73
|
+
@geometry_stack.last << geometry if !@geometry_stack.empty?
|
74
|
+
end
|
75
|
+
#abort a geometry
|
76
|
+
def abort_geometry
|
77
|
+
reset
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'geo_ruby/base/point'
|
2
|
+
require 'geo_ruby/base/line_string'
|
3
|
+
require 'geo_ruby/base/linear_ring'
|
4
|
+
require 'geo_ruby/base/polygon'
|
5
|
+
require 'geo_ruby/base/multi_point'
|
6
|
+
require 'geo_ruby/base/multi_line_string'
|
7
|
+
require 'geo_ruby/base/multi_polygon'
|
8
|
+
require 'geo_ruby/base/geometry_collection'
|
9
|
+
require 'geo_ruby/base/envelope'
|
10
|
+
|
11
|
+
module GeoRuby
|
12
|
+
module Base
|
13
|
+
|
14
|
+
#Raised when an error in the GeoRSS string is detected
|
15
|
+
class GeorssFormatError < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
#Contains tags possibly found on GeoRss Simple geometries
|
19
|
+
class GeorssTags < Struct.new(:featuretypetag,:relationshiptag,:elev,:floor,:radius)
|
20
|
+
end
|
21
|
+
|
22
|
+
#Parses GeoRSS strings
|
23
|
+
#You can also use directly the static method Geometry.from_georss
|
24
|
+
class GeorssParser
|
25
|
+
attr_reader :georss_tags, :geometry
|
26
|
+
|
27
|
+
#Parses the georss geometry passed as argument and notifies the factory of events
|
28
|
+
#The parser assumes
|
29
|
+
def parse(georss,with_tags = false)
|
30
|
+
@geometry = nil
|
31
|
+
@georss_tags = GeorssTags.new
|
32
|
+
parse_geometry(georss,with_tags)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def parse_geometry(georss,with_tags)
|
37
|
+
georss.strip!
|
38
|
+
#check for W3CGeo first
|
39
|
+
if georss =~ /<[^:>]*:lat\s*>([^<]*)</
|
40
|
+
#if valid, it is W3CGeo
|
41
|
+
lat = $1.to_f
|
42
|
+
if georss =~ /<[^:>]*:long\s*>([^<]*)</
|
43
|
+
lon = $1.to_f
|
44
|
+
@geometry = Point.from_x_y(lon,lat)
|
45
|
+
else
|
46
|
+
raise GeorssFormatError.new("Bad W3CGeo GeoRSS format")
|
47
|
+
end
|
48
|
+
elsif georss =~ /^<\s*[^:>]*:where\s*>/
|
49
|
+
#GML format found
|
50
|
+
gml = $'.strip
|
51
|
+
if gml =~ /^<\s*[^:>]*:Point\s*>/
|
52
|
+
#gml point
|
53
|
+
if gml =~ /<\s*[^:>]*:pos\s*>([^<]*)/
|
54
|
+
point = $1.split(" ")
|
55
|
+
#lat comes first
|
56
|
+
@geometry = Point.from_x_y(point[1].to_f,point[0].to_f)
|
57
|
+
else
|
58
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Point")
|
59
|
+
end
|
60
|
+
elsif gml =~ /^<\s*[^:>]*:LineString\s*>/
|
61
|
+
if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/
|
62
|
+
xy = $1.split(" ")
|
63
|
+
@geometry = LineString.new
|
64
|
+
0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
|
65
|
+
else
|
66
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed LineString")
|
67
|
+
end
|
68
|
+
elsif gml =~ /^<\s*[^:>]*:Polygon\s*>/
|
69
|
+
if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/
|
70
|
+
xy = $1.split(" ")
|
71
|
+
@geometry = Polygon.new
|
72
|
+
linear_ring = LinearRing.new
|
73
|
+
@geometry << linear_ring
|
74
|
+
xy = $1.split(" ")
|
75
|
+
0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
|
76
|
+
else
|
77
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Polygon")
|
78
|
+
end
|
79
|
+
elsif gml =~ /^<\s*[^:>]*:Envelope\s*>/
|
80
|
+
if gml =~ /<\s*[^:>]*:lowerCorner\s*>([^<]*)</
|
81
|
+
lc = $1.split(" ").collect { |x| x.to_f}.reverse
|
82
|
+
if gml =~ /<\s*[^:>]*:upperCorner\s*>([^<]*)</
|
83
|
+
uc = $1.split(" ").collect { |x| x.to_f}.reverse
|
84
|
+
@geometry = Envelope.from_coordinates([lc,uc])
|
85
|
+
else
|
86
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope")
|
87
|
+
end
|
88
|
+
else
|
89
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope")
|
90
|
+
end
|
91
|
+
else
|
92
|
+
raise GeorssFormatError.new("Bad GML GeoRSS format: Unknown geometry type")
|
93
|
+
end
|
94
|
+
else
|
95
|
+
#must be simple format
|
96
|
+
if georss =~ /^<\s*[^>:]*:point([^>]*)>(.*)</m
|
97
|
+
tags = $1
|
98
|
+
point = $2.gsub(","," ").split(" ")
|
99
|
+
@geometry = Point.from_x_y(point[1].to_f,point[0].to_f)
|
100
|
+
elsif georss =~ /^<\s*[^>:]*:line([^>]*)>(.*)</m
|
101
|
+
tags = $1
|
102
|
+
@geometry = LineString.new
|
103
|
+
xy = $2.gsub(","," ").split(" ")
|
104
|
+
0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
|
105
|
+
elsif georss =~ /^<\s*[^>:]*:polygon([^>]*)>(.*)</m
|
106
|
+
tags = $1
|
107
|
+
@geometry = Polygon.new
|
108
|
+
linear_ring = LinearRing.new
|
109
|
+
@geometry << linear_ring
|
110
|
+
xy = $2.gsub(","," ").split(" ")
|
111
|
+
0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
|
112
|
+
elsif georss =~ /^<\s*[^>:]*:box([^>]*)>(.*)</m
|
113
|
+
tags = $1
|
114
|
+
corners = []
|
115
|
+
xy = $2.gsub(","," ").split(" ")
|
116
|
+
0.upto(xy.size/2 - 1) {|index| corners << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
|
117
|
+
@geometry = Envelope.from_points(corners)
|
118
|
+
else
|
119
|
+
raise GeorssFormatError.new("Bad Simple GeoRSS format: Unknown geometry type")
|
120
|
+
end
|
121
|
+
|
122
|
+
#geometry found: parse tags
|
123
|
+
return unless with_tags
|
124
|
+
|
125
|
+
@georss_tags.featuretypetag = $1 if tags =~ /featuretypetag=['"]([^"']*)['"]/
|
126
|
+
@georss_tags.relationshiptag = $1 if tags =~ /relationshiptag=['"]([^'"]*)['"]/
|
127
|
+
@georss_tags.elev = $1.to_f if tags =~ /elev=['"]([^'"]*)['"]/
|
128
|
+
@georss_tags.floor = $1.to_i if tags =~ /floor=['"]([^'"]*)['"]/
|
129
|
+
@georss_tags.radius = $1.to_f if tags =~ /radius=['"]([^'"]*)['"]/
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module GeoRuby
|
2
|
+
module Base
|
3
|
+
#indicates the presence of Z coordinates in EWKB strings
|
4
|
+
Z_MASK=0x80000000
|
5
|
+
#indicates the presence of M coordinates in EWKB strings.
|
6
|
+
M_MASK=0x40000000
|
7
|
+
#indicate the presence of a SRID in EWKB strings.
|
8
|
+
SRID_MASK=0x20000000
|
9
|
+
#GeoRSS namespace
|
10
|
+
GEORSS_NS = "http://www.georss.org/georss"
|
11
|
+
#GML Namespace
|
12
|
+
GML_NS = "http://www.opengis.net/gml"
|
13
|
+
#W3CGeo Namespace
|
14
|
+
W3CGEO_NS = "http://www.w3.org/2003/01/geo/wgs84_pos#"
|
15
|
+
#KML Namespace
|
16
|
+
KML_NS = "http://earth.google.com/kml/2.1"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require "geo_ruby/base/geometry"
|
2
|
+
|
3
|
+
module GeoRuby
|
4
|
+
module Base
|
5
|
+
#Represents a line string as an array of points (see Point).
|
6
|
+
class LineString < Geometry
|
7
|
+
#the list of points forming the line string
|
8
|
+
attr_reader :points
|
9
|
+
|
10
|
+
def initialize(srid= @@default_srid,with_z=false,with_m=false)
|
11
|
+
super(srid,with_z,with_m)
|
12
|
+
@points=[]
|
13
|
+
end
|
14
|
+
|
15
|
+
#Delegate the unknown methods to the points array
|
16
|
+
def method_missing(method_name,*args,&b)
|
17
|
+
@points.send(method_name,*args,&b)
|
18
|
+
end
|
19
|
+
|
20
|
+
#tests if the line string is closed
|
21
|
+
def is_closed
|
22
|
+
#a bit naive...
|
23
|
+
@points.first == @points.last
|
24
|
+
end
|
25
|
+
alias :closed? :is_closed
|
26
|
+
|
27
|
+
#Bounding box in 2D/3D. Returns an array of 2 points
|
28
|
+
def bounding_box
|
29
|
+
max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
|
30
|
+
if(with_z)
|
31
|
+
max_z, min_z = -Float::MAX,Float::MAX
|
32
|
+
each do |point|
|
33
|
+
max_y = point.y if point.y > max_y
|
34
|
+
min_y = point.y if point.y < min_y
|
35
|
+
max_x = point.x if point.x > max_x
|
36
|
+
min_x = point.x if point.x < min_x
|
37
|
+
max_z = point.z if point.z > max_z
|
38
|
+
min_z = point.z if point.z < min_z
|
39
|
+
end
|
40
|
+
[Point.from_x_y_z(min_x,min_y,min_z),Point.from_x_y_z(max_x,max_y,max_z)]
|
41
|
+
else
|
42
|
+
each do |point|
|
43
|
+
max_y = point.y if point.y > max_y
|
44
|
+
min_y = point.y if point.y < min_y
|
45
|
+
max_x = point.x if point.x > max_x
|
46
|
+
min_x = point.x if point.x < min_x
|
47
|
+
end
|
48
|
+
[Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def m_range
|
53
|
+
if with_m
|
54
|
+
max_m, min_m = -Float::MAX, Float::MAX
|
55
|
+
each do |point|
|
56
|
+
max_m = point.m if point.m > max_m
|
57
|
+
min_m = point.m if point.m < min_m
|
58
|
+
end
|
59
|
+
[min_m,max_m]
|
60
|
+
else
|
61
|
+
[0,0]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#call to native Geo intersect, return true or false
|
66
|
+
def intersects?(other_line_string)
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def spherical_distance
|
71
|
+
total = 0
|
72
|
+
@points.each_with_index do |p,i|
|
73
|
+
total += p.spherical_distance(@points[i+1]) if @points[i+1]
|
74
|
+
end
|
75
|
+
total
|
76
|
+
end
|
77
|
+
|
78
|
+
def euclidian_distance
|
79
|
+
total = 0
|
80
|
+
@points.each_with_index do |p,i|
|
81
|
+
total += p.euclidian_distance(@points[i+1]) if @points[i+1]
|
82
|
+
end
|
83
|
+
total
|
84
|
+
end
|
85
|
+
|
86
|
+
#Tests the equality of line strings
|
87
|
+
def ==(other_line_string)
|
88
|
+
if(other_line_string.class != self.class or
|
89
|
+
other_line_string.length != self.length)
|
90
|
+
false
|
91
|
+
else
|
92
|
+
index=0
|
93
|
+
while index<length
|
94
|
+
return false if self[index] != other_line_string[index]
|
95
|
+
index+=1
|
96
|
+
end
|
97
|
+
true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
#Binary representation of a line string
|
102
|
+
def binary_representation(allow_z=true,allow_m=true) #:nodoc:
|
103
|
+
rep = [length].pack("V")
|
104
|
+
each {|point| rep << point.binary_representation(allow_z,allow_m) }
|
105
|
+
rep
|
106
|
+
end
|
107
|
+
|
108
|
+
#WKB geometry type
|
109
|
+
def binary_geometry_type #:nodoc:
|
110
|
+
2
|
111
|
+
end
|
112
|
+
|
113
|
+
#Text representation of a line string
|
114
|
+
def text_representation(allow_z=true,allow_m=true) #:nodoc:
|
115
|
+
@points.collect{|point| point.text_representation(allow_z,allow_m) }.join(",")
|
116
|
+
end
|
117
|
+
#WKT geometry type
|
118
|
+
def text_geometry_type #:nodoc:
|
119
|
+
"LINESTRING"
|
120
|
+
end
|
121
|
+
|
122
|
+
#georss simple representation
|
123
|
+
def georss_simple_representation(options) #:nodoc:
|
124
|
+
georss_ns = options[:georss_ns] || "georss"
|
125
|
+
geom_attr = options[:geom_attr]
|
126
|
+
"<#{georss_ns}:line#{geom_attr}>" + georss_poslist + "</#{georss_ns}:line>\n"
|
127
|
+
end
|
128
|
+
#georss w3c representation : outputs the first point of the line
|
129
|
+
def georss_w3cgeo_representation(options) #:nodoc:
|
130
|
+
w3cgeo_ns = options[:w3cgeo_ns] || "geo"
|
131
|
+
"<#{w3cgeo_ns}:lat>#{self[0].y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{self[0].x}</#{w3cgeo_ns}:long>\n"
|
132
|
+
end
|
133
|
+
#georss gml representation
|
134
|
+
def georss_gml_representation(options) #:nodoc:
|
135
|
+
georss_ns = options[:georss_ns] || "georss"
|
136
|
+
gml_ns = options[:gml_ns] || "gml"
|
137
|
+
|
138
|
+
result = "<#{georss_ns}:where>\n<#{gml_ns}:LineString>\n<#{gml_ns}:posList>\n"
|
139
|
+
result += georss_poslist
|
140
|
+
result += "\n</#{gml_ns}:posList>\n</#{gml_ns}:LineString>\n</#{georss_ns}:where>\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
def georss_poslist #:nodoc:
|
144
|
+
map {|point| "#{point.y} #{point.x}"}.join(" ")
|
145
|
+
end
|
146
|
+
|
147
|
+
#outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
|
148
|
+
#<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
|
149
|
+
#it won't be used by GE anyway: clampToGround is the default)
|
150
|
+
def kml_representation(options = {}) #:nodoc:
|
151
|
+
result = "<LineString#{options[:id_attr]}>\n"
|
152
|
+
result += options[:geom_data] if options[:geom_data]
|
153
|
+
result += "<coordinates>"
|
154
|
+
result += kml_poslist(options)
|
155
|
+
result += "</coordinates>\n"
|
156
|
+
result += "</LineString>\n"
|
157
|
+
end
|
158
|
+
|
159
|
+
def kml_poslist(options) #:nodoc:
|
160
|
+
pos_list = if options[:allow_z]
|
161
|
+
map {|point| "#{point.x},#{point.y},#{options[:fixed_z] || point.z || 0}" }
|
162
|
+
else
|
163
|
+
map {|point| "#{point.x},#{point.y}" }
|
164
|
+
end
|
165
|
+
pos_list.reverse! if(options[:reverse])
|
166
|
+
pos_list.join(" ")
|
167
|
+
end
|
168
|
+
|
169
|
+
#Creates a new line string. Accept an array of points as argument
|
170
|
+
def self.from_points(points,srid=@@default_srid,with_z=false,with_m=false)
|
171
|
+
line_string = new(srid,with_z,with_m)
|
172
|
+
line_string.concat(points)
|
173
|
+
line_string
|
174
|
+
end
|
175
|
+
|
176
|
+
#Creates a new line string. Accept a sequence of points as argument : ((x,y)...(x,y))
|
177
|
+
def self.from_coordinates(points,srid=@@default_srid,with_z=false,with_m=false)
|
178
|
+
line_string = new(srid,with_z,with_m)
|
179
|
+
line_string.concat( points.map {|p| Point.from_coordinates(p,srid,with_z,with_m) } )
|
180
|
+
line_string
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|