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.
Files changed (54) hide show
  1. data/History.txt +4 -0
  2. data/LICENSE +21 -0
  3. data/README.txt +59 -0
  4. data/Rakefile +49 -0
  5. data/VERSION.yml +4 -0
  6. data/lib/geo_ruby.rb +21 -0
  7. data/lib/geo_ruby/base/envelope.rb +167 -0
  8. data/lib/geo_ruby/base/ewkb_parser.rb +216 -0
  9. data/lib/geo_ruby/base/ewkt_parser.rb +336 -0
  10. data/lib/geo_ruby/base/geometry.rb +234 -0
  11. data/lib/geo_ruby/base/geometry_collection.rb +136 -0
  12. data/lib/geo_ruby/base/geometry_factory.rb +81 -0
  13. data/lib/geo_ruby/base/georss_parser.rb +135 -0
  14. data/lib/geo_ruby/base/helper.rb +18 -0
  15. data/lib/geo_ruby/base/line_string.rb +184 -0
  16. data/lib/geo_ruby/base/linear_ring.rb +12 -0
  17. data/lib/geo_ruby/base/multi_line_string.rb +39 -0
  18. data/lib/geo_ruby/base/multi_point.rb +41 -0
  19. data/lib/geo_ruby/base/multi_polygon.rb +37 -0
  20. data/lib/geo_ruby/base/point.rb +310 -0
  21. data/lib/geo_ruby/base/polygon.rb +150 -0
  22. data/lib/geo_ruby/shp4r/dbf.rb +180 -0
  23. data/lib/geo_ruby/shp4r/shp.rb +701 -0
  24. data/spec/data/multipoint.dbf +0 -0
  25. data/spec/data/multipoint.shp +0 -0
  26. data/spec/data/multipoint.shx +0 -0
  27. data/spec/data/point.dbf +0 -0
  28. data/spec/data/point.shp +0 -0
  29. data/spec/data/point.shx +0 -0
  30. data/spec/data/polygon.dbf +0 -0
  31. data/spec/data/polygon.shp +0 -0
  32. data/spec/data/polygon.shx +0 -0
  33. data/spec/data/polyline.dbf +0 -0
  34. data/spec/data/polyline.shp +0 -0
  35. data/spec/data/polyline.shx +0 -0
  36. data/spec/geo_ruby/base/envelope_spec.rb +45 -0
  37. data/spec/geo_ruby/base/ewkb_parser_spec.rb +158 -0
  38. data/spec/geo_ruby/base/ewkt_parser_spec.rb +179 -0
  39. data/spec/geo_ruby/base/geometry_collection_spec.rb +55 -0
  40. data/spec/geo_ruby/base/geometry_factory_spec.rb +11 -0
  41. data/spec/geo_ruby/base/geometry_spec.rb +32 -0
  42. data/spec/geo_ruby/base/georss_parser_spec.rb +218 -0
  43. data/spec/geo_ruby/base/line_string_spec.rb +208 -0
  44. data/spec/geo_ruby/base/linear_ring_spec.rb +14 -0
  45. data/spec/geo_ruby/base/multi_line_string_spec.rb +35 -0
  46. data/spec/geo_ruby/base/multi_point_spec.rb +29 -0
  47. data/spec/geo_ruby/base/multi_polygon_spec.rb +35 -0
  48. data/spec/geo_ruby/base/point_spec.rb +275 -0
  49. data/spec/geo_ruby/base/polygon_spec.rb +108 -0
  50. data/spec/geo_ruby/shp4r/shp_spec.rb +238 -0
  51. data/spec/geo_ruby_spec.rb +27 -0
  52. data/spec/spec.opts +6 -0
  53. data/spec/spec_helper.rb +12 -0
  54. metadata +123 -0
@@ -0,0 +1,12 @@
1
+ require 'geo_ruby/base/line_string'
2
+
3
+ module GeoRuby
4
+ module Base
5
+ #Represents a linear ring, which is a closed line string (see LineString). Currently, no check is performed to verify if the linear ring is really closed.
6
+ class LinearRing < LineString
7
+ def initialize(srid= @@default_srid,with_z=false,with_m=false)
8
+ super(srid,with_z,with_m)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ require 'geo_ruby/base/geometry_collection'
2
+
3
+ module GeoRuby
4
+ module Base
5
+ #Represents a group of line strings (see LineString).
6
+ class MultiLineString < GeometryCollection
7
+ def initialize(srid = @@default_srid,with_z=false,with_m=false)
8
+ super(srid)
9
+ end
10
+
11
+ def binary_geometry_type #:nodoc:
12
+ 5
13
+ end
14
+
15
+ #Text representation of a multi line string
16
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
17
+ @geometries.collect{|line_string| "(" + line_string.text_representation(allow_z,allow_m) + ")" }.join(",")
18
+ end
19
+ #WKT geometry type
20
+ def text_geometry_type #:nodoc:
21
+ "MULTILINESTRING"
22
+ end
23
+
24
+ #Creates a new multi line string from an array of line strings
25
+ def self.from_line_strings(line_strings,srid=@@default_srid,with_z=false,with_m=false)
26
+ multi_line_string = new(srid,with_z,with_m)
27
+ multi_line_string.concat(line_strings)
28
+ multi_line_string
29
+ end
30
+
31
+ #Creates a new multi line string from sequences of points : (((x,y)...(x,y)),((x,y)...(x,y)))
32
+ def self.from_coordinates(point_sequences,srid=@@default_srid,with_z=false,with_m=false)
33
+ multi_line_string = new(srid,with_z,with_m)
34
+ multi_line_string.concat(point_sequences.collect {|points| LineString.from_coordinates(points,srid,with_z,with_m) })
35
+ multi_line_string
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ require 'geo_ruby/base/geometry_collection'
2
+
3
+ module GeoRuby
4
+ module Base
5
+ #Represents a group of points (see Point).
6
+ class MultiPoint < GeometryCollection
7
+
8
+ def initialize(srid= @@default_srid,with_z=false,with_m=false)
9
+ super(srid,with_z,with_m)
10
+ end
11
+
12
+ def binary_geometry_type #:nodoc:
13
+ 4
14
+ end
15
+
16
+ #Text representation of a MultiPoint
17
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
18
+ "(" + @geometries.collect{|point| point.text_representation(allow_z,allow_m)}.join("),(") + ")"
19
+ end
20
+ #WKT geoemtry type
21
+ def text_geometry_type #:nodoc:
22
+ "MULTIPOINT"
23
+ end
24
+
25
+ #Creates a new multi point from an array of points
26
+ def self.from_points(points,srid= @@default_srid,with_z=false,with_m=false)
27
+ multi_point= new(srid,with_z,with_m)
28
+ multi_point.concat(points)
29
+ multi_point
30
+ end
31
+
32
+ #Creates a new multi point from a list of point coordinates : ((x,y)...(x,y))
33
+ def self.from_coordinates(points,srid= @@default_srid,with_z=false,with_m=false)
34
+ multi_point= new(srid,with_z,with_m)
35
+ multi_point.concat(points.collect {|point| Point.from_coordinates(point,srid,with_z,with_m)})
36
+ multi_point
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ require 'geo_ruby/base/geometry_collection'
2
+
3
+ module GeoRuby
4
+ module Base
5
+ #Represents a group of polygons (see Polygon).
6
+ class MultiPolygon < GeometryCollection
7
+ def initialize(srid = @@default_srid,with_z=false,with_m=false)
8
+ super(srid)
9
+ end
10
+
11
+ def binary_geometry_type #:nodoc:
12
+ 6
13
+ end
14
+ #Text representation of a MultiPolygon
15
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
16
+ @geometries.collect{|polygon| "(" + polygon.text_representation(allow_z,allow_m) + ")"}.join(",")
17
+ end
18
+ #WKT geometry type
19
+ def text_geometry_type #:nodoc:
20
+ "MULTIPOLYGON"
21
+ end
22
+
23
+ #Creates a multi polygon from an array of polygons
24
+ def self.from_polygons(polygons,srid=@@default_srid,with_z=false,with_m=false)
25
+ multi_polygon = new(srid,with_z,with_m)
26
+ multi_polygon.concat(polygons)
27
+ multi_polygon
28
+ end
29
+ #Creates a multi polygon from sequences of points : ((((x,y)...(x,y)),((x,y)...(x,y)),((x,y)...(x,y)))
30
+ def self.from_coordinates(point_sequence_sequences,srid= @@default_srid,with_z=false,with_m=false)
31
+ multi_polygon = new(srid,with_z,with_m)
32
+ multi_polygon.concat( point_sequence_sequences.collect {|point_sequences| Polygon.from_coordinates(point_sequences,srid,with_z,with_m) } )
33
+ multi_polygon
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,310 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "geo_ruby/base/geometry"
3
+
4
+ module GeoRuby
5
+ module Base
6
+ #Represents a point. It is in 3D if the Z coordinate is not +nil+.
7
+ class Point < Geometry
8
+ DEG2RAD = 0.0174532925199433
9
+ attr_accessor :x,:y,:z,:m
10
+ attr_reader :r, :t # radium and theta
11
+
12
+ #if you prefer calling the coordinates lat and lon (or lng, for GeoKit compatibility)
13
+ alias :lon :x
14
+ alias :lng :x
15
+ alias :lat :y
16
+ alias :rad :r
17
+ alias :tet :t
18
+ alias :tetha :t
19
+
20
+ def initialize(srid=@@default_srid,with_z=false,with_m=false)
21
+ super(srid,with_z,with_m)
22
+ @x = @y = 0.0
23
+ @z=0.0 #default value : meaningful if with_z
24
+ @m=0.0 #default value : meaningful if with_m
25
+ end
26
+ #sets all coordinates in one call. Use the +m+ accessor to set the m.
27
+ def set_x_y_z(x,y,z)
28
+ @x=x
29
+ @y=y
30
+ @z=z
31
+ self
32
+ end
33
+ alias :set_lon_lat_z :set_x_y_z
34
+
35
+ #sets all coordinates of a 2D point in one call
36
+ def set_x_y(x,y)
37
+ @x=x
38
+ @y=y
39
+ self
40
+ end
41
+ alias :set_lon_lat :set_x_y
42
+
43
+ #Return the distance between the 2D points (ie taking care only of the x and y coordinates), assuming
44
+ #the points are in projected coordinates. Euclidian distance in whatever unit the x and y ordinates are.
45
+ def euclidian_distance(point)
46
+ Math.sqrt((point.x - x)**2 + (point.y - y)**2)
47
+ end
48
+
49
+ #Returns the sperical distance in meters, with a radius of 6471000m, with the haversine law.
50
+ #Assumes x is the lon and y the lat, in degrees (Changed in version 1.1).
51
+ #The user has to make sure using this distance makes sense (ie she should be in latlon coordinates)
52
+ def spherical_distance(point,r=6370997.0)
53
+ radlat_from = lat * DEG2RAD
54
+ radlat_to = point.lat * DEG2RAD
55
+ dlat = (point.lat - lat) * DEG2RAD / 2
56
+ dlon = (point.lon - lon) * DEG2RAD / 2
57
+
58
+ a = Math.sin(dlat)**2 + Math.cos(radlat_from) * Math.cos(radlat_to) * Math.sin(dlon)**2
59
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
60
+ r * c
61
+ end
62
+
63
+ #Ellipsoidal distance in m using Vincenty's formula. Lifted entirely from Chris Veness's code at http://www.movable-type.co.uk/scripts/LatLongVincenty.html and adapted for Ruby. Assumes the x and y are the lon and lat in degrees.
64
+ #a is the semi-major axis (equatorial radius) of the ellipsoid
65
+ #b is the semi-minor axis (polar radius) of the ellipsoid
66
+ #Their values by default are set to the ones of the WGS84 ellipsoid
67
+ def ellipsoidal_distance(point, a = 6378137.0, b = 6356752.3142)
68
+ f = (a-b) / a
69
+ l = (point.lon - lon) * DEG2RAD
70
+
71
+ u1 = Math.atan((1-f) * Math.tan(lat * DEG2RAD ))
72
+ u2 = Math.atan((1-f) * Math.tan(point.lat * DEG2RAD))
73
+ sinU1 = Math.sin(u1)
74
+ cosU1 = Math.cos(u1)
75
+ sinU2 = Math.sin(u2)
76
+ cosU2 = Math.cos(u2)
77
+
78
+ lambda = l
79
+ lambdaP = 2 * Math::PI
80
+ iterLimit = 20
81
+
82
+ while (lambda-lambdaP).abs > 1e-12 && --iterLimit>0
83
+ sinLambda = Math.sin(lambda)
84
+ cosLambda = Math.cos(lambda)
85
+ sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda))
86
+
87
+ return 0 if sinSigma == 0 #coincident points
88
+
89
+ cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda
90
+ sigma = Math.atan2(sinSigma, cosSigma)
91
+ sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma
92
+ cosSqAlpha = 1 - sinAlpha*sinAlpha
93
+ cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha
94
+
95
+ cos2SigmaM = 0 if (cos2SigmaM.nan?) #equatorial line: cosSqAlpha=0
96
+
97
+ c = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha))
98
+ lambdaP = lambda
99
+ lambda = l + (1-c) * f * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)))
100
+ end
101
+ return NaN if iterLimit==0 #formula failed to converge
102
+
103
+ uSq = cosSqAlpha * (a*a - b*b) / (b*b)
104
+ a_bis = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
105
+ b_bis = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
106
+ deltaSigma = b_bis * sinSigma*(cos2SigmaM + b_bis/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- b_bis/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)))
107
+
108
+ b*a_bis*(sigma-deltaSigma)
109
+ end
110
+
111
+ #Bounding box in 2D/3D. Returns an array of 2 points
112
+ def bounding_box
113
+ unless with_z
114
+ [Point.from_x_y(@x,@y),Point.from_x_y(@x,@y)]
115
+ else
116
+ [Point.from_x_y_z(@x,@y,@z),Point.from_x_y_z(@x,@y,@z)]
117
+ end
118
+ end
119
+
120
+ def m_range
121
+ [@m,@m]
122
+ end
123
+
124
+ #tests the equality of the position of points + m
125
+ def ==(other_point)
126
+ if other_point.class != self.class
127
+ false
128
+ else
129
+ @x == other_point.x and @y == other_point.y and @z == other_point.z and @m == other_point.m
130
+ end
131
+ end
132
+
133
+ #binary representation of a point. It lacks some headers to be a valid EWKB representation.
134
+ def binary_representation(allow_z=true,allow_m=true) #:nodoc:
135
+ bin_rep = [@x,@y].pack("EE")
136
+ bin_rep += [@z].pack("E") if @with_z and allow_z #Default value so no crash
137
+ bin_rep += [@m].pack("E") if @with_m and allow_m #idem
138
+ bin_rep
139
+ end
140
+ #WKB geometry type of a point
141
+ def binary_geometry_type#:nodoc:
142
+ 1
143
+ end
144
+
145
+ #text representation of a point
146
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
147
+ tex_rep = "#{@x} #{@y}"
148
+ tex_rep += " #{@z}" if @with_z and allow_z
149
+ tex_rep += " #{@m}" if @with_m and allow_m
150
+ tex_rep
151
+ end
152
+ #WKT geometry type of a point
153
+ def text_geometry_type #:nodoc:
154
+ "POINT"
155
+ end
156
+
157
+ #georss simple representation
158
+ def georss_simple_representation(options) #:nodoc:
159
+ georss_ns = options[:georss_ns] || "georss"
160
+ geom_attr = options[:geom_attr]
161
+ "<#{georss_ns}:point#{geom_attr}>#{y} #{x}</#{georss_ns}:point>\n"
162
+ end
163
+ #georss w3c representation
164
+ def georss_w3cgeo_representation(options) #:nodoc:
165
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
166
+ "<#{w3cgeo_ns}:lat>#{y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{x}</#{w3cgeo_ns}:long>\n"
167
+ end
168
+ #georss gml representation
169
+ def georss_gml_representation(options) #:nodoc:
170
+ georss_ns = options[:georss_ns] || "georss"
171
+ gml_ns = options[:gml_ns] || "gml"
172
+ result = "<#{georss_ns}:where>\n<#{gml_ns}:Point>\n<#{gml_ns}:pos>"
173
+ result += "#{y} #{x}"
174
+ result += "</#{gml_ns}:pos>\n</#{gml_ns}:Point>\n</#{georss_ns}:where>\n"
175
+ end
176
+
177
+ #outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
178
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
179
+ #it won't be used by GE anyway: clampToGround is the default)
180
+ def kml_representation(options = {}) #:nodoc:
181
+ result = "<Point#{options[:id_attr]}>\n"
182
+ result += options[:geom_data] if options[:geom_data]
183
+ result += "<coordinates>#{x},#{y}"
184
+ result += ",#{options[:fixed_z] || z ||0}" if options[:allow_z]
185
+ result += "</coordinates>\n"
186
+ result += "</Point>\n"
187
+ end
188
+
189
+ # Outputs the geometry in coordinates format:
190
+ # 47°52′48″, -20°06′00″
191
+ def as_latlong(opts = { })
192
+ val = []
193
+ [x,y].each_with_index do |l,i|
194
+ deg = l.to_i.abs
195
+ min = (60 * (l.abs - deg)).to_i
196
+ labs = (l * 1000000).abs / 1000000
197
+ sec = ((((labs - labs.to_i) * 60) - ((labs - labs.to_i) * 60).to_i) * 100000) * 60 / 100000
198
+ str = opts[:full] ? "%.i°%.2i′%05.2f″" : "%.i°%.2i′%02.0f″"
199
+ if opts[:coord]
200
+ out = str % [deg,min,sec]
201
+ if i == 0
202
+ out += l > 0 ? "N" : "S"
203
+ else
204
+ out += l > 0 ? "E" : "W"
205
+ end
206
+ val << out
207
+ else
208
+ val << str % [l.to_i, min, sec]
209
+ end
210
+ end
211
+ val.join(", ")
212
+ end
213
+
214
+ #Polar stuff
215
+ #http://www.engineeringtoolbox.com/converting-cartesian-polar-coordinates-d_1347.html
216
+ #http://rcoordinate.rubyforge.org/svn/point.rb
217
+ # outputs radium
218
+ def r; Math.sqrt(x**2 + y**2); end
219
+
220
+ #outputs theta
221
+ def theta_rad
222
+ if @x.zero?
223
+ @y < 0 ? 3 * Math::PI / 2 : Math::PI / 2
224
+ else
225
+ th = Math.atan(@y/@x)
226
+ th += 2 * Math::PI if r > 0
227
+ end
228
+ end
229
+
230
+ def theta_deg
231
+ theta_rad / DEG2RAD
232
+ end
233
+
234
+ #outputs an array containing polar distance and theta
235
+ def as_polar
236
+ [r,t]
237
+ end
238
+
239
+ #creates a point from an array of coordinates
240
+ def self.from_coordinates(coords,srid=@@default_srid,with_z=false,with_m=false)
241
+ if ! (with_z or with_m)
242
+ from_x_y(coords[0],coords[1],srid)
243
+ elsif with_z and with_m
244
+ from_x_y_z_m(coords[0],coords[1],coords[2],coords[3],srid)
245
+ elsif with_z
246
+ from_x_y_z(coords[0],coords[1],coords[2],srid)
247
+ else
248
+ from_x_y_m(coords[0],coords[1],coords[2],srid)
249
+ end
250
+ end
251
+
252
+ #creates a point from the X and Y coordinates
253
+ def self.from_x_y(x,y,srid=@@default_srid)
254
+ point= new(srid)
255
+ point.set_x_y(x,y)
256
+ end
257
+
258
+ #creates a point from the X, Y and Z coordinates
259
+ def self.from_x_y_z(x,y,z,srid=@@default_srid)
260
+ point= new(srid,true)
261
+ point.set_x_y_z(x,y,z)
262
+ end
263
+
264
+ #creates a point from the X, Y and M coordinates
265
+ def self.from_x_y_m(x,y,m,srid=@@default_srid)
266
+ point= new(srid,false,true)
267
+ point.m=m
268
+ point.set_x_y(x,y)
269
+ end
270
+
271
+ #creates a point from the X, Y, Z and M coordinates
272
+ def self.from_x_y_z_m(x,y,z,m,srid=@@default_srid)
273
+ point= new(srid,true,true)
274
+ point.m=m
275
+ point.set_x_y_z(x,y,z)
276
+ end
277
+
278
+ #creates a point using polar coordinates
279
+ #r and theta(degrees)
280
+ def self.from_r_t(r,t,srid=@@default_srid)
281
+ t *= DEG2RAD
282
+ x = r * Math.cos(t)
283
+ y = r * Math.sin(t)
284
+ point= new(srid)
285
+ point.set_x_y(x,y)
286
+ end
287
+
288
+ #creates a point using coordinates like 22`34 23.45N
289
+ def self.from_latlong(lat,lon,srid=@@default_srid)
290
+ p = [lat,lon].map do |l|
291
+ sig, deg, min, sec, cen = l.scan(/(-)?(\d{1,2})\D*(\d{2})\D*(\d{2})(\D*(\d{1,3}))?/).flatten
292
+ sig = true if l =~ /W|S/
293
+ dec = deg.to_i + (min.to_i * 60 + "#{sec}#{cen}".to_f) / 3600
294
+ sig ? dec * -1 : dec
295
+ end
296
+ point= new(srid)
297
+ point.set_x_y(p[0],p[1])
298
+ end
299
+
300
+ #aliasing the constructors in case you want to use lat/lon instead of y/x
301
+ class << self
302
+ alias :from_lon_lat :from_x_y
303
+ alias :from_lon_lat_z :from_x_y_z
304
+ alias :from_lon_lat_m :from_x_y_m
305
+ alias :from_lon_lat_z_m :from_x_y_z_m
306
+ alias :from_rad_tet :from_r_t
307
+ end
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,150 @@
1
+ require 'geo_ruby/base/geometry'
2
+
3
+ module GeoRuby
4
+ module Base
5
+ #Represents a polygon as an array of linear rings (see LinearRing). No check is performed regarding the validity of the geometries forming the polygon.
6
+ class Polygon < Geometry
7
+ #the list of rings forming the polygon
8
+ attr_reader :rings
9
+
10
+ def initialize(srid = @@default_srid,with_z=false,with_m=false)
11
+ super(srid,with_z,with_m)
12
+ @rings = []
13
+ end
14
+
15
+ #Delegate the unknown methods to the rings array
16
+ def method_missing(method_name,*args,&b)
17
+ @rings.send(method_name,*args,&b)
18
+ end
19
+
20
+ #Bounding box in 2D/3D. Returns an array of 2 points
21
+ def bounding_box
22
+ unless with_z
23
+ @rings[0].bounding_box
24
+ else
25
+ result = @rings[0].bounding_box #valid for x and y
26
+ max_z, min_z = result[1].z, result[0].z
27
+ 1.upto(size - 1) do |index|
28
+ bbox = @rings[index].bounding_box
29
+ sw = bbox[0]
30
+ ne = bbox[1]
31
+ max_z = ne.z if ne.z > max_z
32
+ min_z = sw.z if sw.z < min_z
33
+ end
34
+ result[1].z, result[0].z = max_z, min_z
35
+ result
36
+ end
37
+ end
38
+
39
+ def m_range
40
+ if with_m
41
+ max_m, min_m = -Float::MAX, Float::MAX
42
+ each do |lr|
43
+ lrmr = lr.m_range
44
+ max_m = lrmr[1] if lrmr[1] > max_m
45
+ min_m = lrmr[0] if lrmr[0] < min_m
46
+ end
47
+ [min_m,max_m]
48
+ else
49
+ [0,0]
50
+ end
51
+ end
52
+
53
+ #tests for other equality. The SRID is not taken into account.
54
+ def ==(other_polygon)
55
+ if other_polygon.class != self.class or
56
+ length != other_polygon.length
57
+ false
58
+ else
59
+ index=0
60
+ while index<length
61
+ return false if self[index] != other_polygon[index]
62
+ index+=1
63
+ end
64
+ true
65
+ end
66
+ end
67
+ #binary representation of a polygon, without the headers neccessary for a valid WKB string
68
+ def binary_representation(allow_z=true,allow_m=true)
69
+ rep = [length].pack("V")
70
+ each {|linear_ring| rep << linear_ring.binary_representation(allow_z,allow_m)}
71
+ rep
72
+ end
73
+ #WKB geometry type
74
+ def binary_geometry_type
75
+ 3
76
+ end
77
+
78
+ #Text representation of a polygon
79
+ def text_representation(allow_z=true,allow_m=true)
80
+ @rings.collect{|line_string| "(" + line_string.text_representation(allow_z,allow_m) + ")" }.join(",")
81
+ end
82
+ #WKT geometry type
83
+ def text_geometry_type
84
+ "POLYGON"
85
+ end
86
+
87
+ #georss simple representation : outputs only the outer ring
88
+ def georss_simple_representation(options)
89
+ georss_ns = options[:georss_ns] || "georss"
90
+ geom_attr = options[:geom_attr]
91
+ "<#{georss_ns}:polygon#{geom_attr}>" + self[0].georss_poslist + "</#{georss_ns}:polygon>\n"
92
+ end
93
+ #georss w3c representation : outputs the first point of the outer ring
94
+ def georss_w3cgeo_representation(options)
95
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
96
+
97
+ "<#{w3cgeo_ns}:lat>#{self[0][0].y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{self[0][0].x}</#{w3cgeo_ns}:long>\n"
98
+ end
99
+ #georss gml representation
100
+ def georss_gml_representation(options)
101
+ georss_ns = options[:georss_ns] || "georss"
102
+ gml_ns = options[:gml_ns] || "gml"
103
+
104
+ result = "<#{georss_ns}:where>\n<#{gml_ns}:Polygon>\n<#{gml_ns}:exterior>\n<#{gml_ns}:LinearRing>\n<#{gml_ns}:posList>\n" + self[0].georss_poslist + "\n</#{gml_ns}:posList>\n</#{gml_ns}:LinearRing>\n</#{gml_ns}:exterior>\n</#{gml_ns}:Polygon>\n</#{georss_ns}:where>\n"
105
+ end
106
+
107
+ #outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
108
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
109
+ #it won't be used by GE anyway: clampToGround is the default)
110
+ def kml_representation(options = {})
111
+ result = "<Polygon#{options[:id_attr]}>\n"
112
+ result += options[:geom_data] if options[:geom_data]
113
+ rings.each_with_index do |ring, i|
114
+ if i == 0
115
+ boundary = "outerBoundaryIs"
116
+ else
117
+ boundary = "innerBoundaryIs"
118
+ end
119
+ result += "<#{boundary}><LinearRing><coordinates>\n"
120
+ result += ring.kml_poslist(options)
121
+ result += "\n</coordinates></LinearRing></#{boundary}>\n"
122
+ end
123
+ result += "</Polygon>\n"
124
+ end
125
+
126
+ #creates a new polygon. Accepts an array of linear strings as argument
127
+ def self.from_linear_rings(linear_rings,srid = @@default_srid,with_z=false,with_m=false)
128
+ polygon = new(srid,with_z,with_m)
129
+ polygon.concat(linear_rings)
130
+ polygon
131
+ end
132
+
133
+ #creates a new polygon. Accepts a sequence of points as argument : ((x,y)....(x,y)),((x,y).....(x,y))
134
+ def self.from_coordinates(point_sequences,srid=@@default_srid,with_z=false,with_m=false)
135
+ polygon = new(srid,with_z,with_m)
136
+ polygon.concat( point_sequences.collect {|points| LinearRing.from_coordinates(points,srid,with_z,with_m) } )
137
+ polygon
138
+ end
139
+
140
+ #creates a new polygon from a list of Points (pt1....ptn),(pti....ptj)
141
+ def self.from_points(point_sequences, srid=@@default_srid,with_z=false,with_m=false)
142
+ polygon = new(srid,with_z,with_m)
143
+ polygon.concat( point_sequences.collect {|points| LinearRing.from_points(points,srid,with_z,with_m) } )
144
+ polygon
145
+
146
+ end
147
+
148
+ end
149
+ end
150
+ end