GeoRuby 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,5 +1,5 @@
1
1
  =GeoRuby
2
- This is GeoRuby 0.2.1. It is intended as a holder for data returned from PostGIS and the Spatial Extensions of MySql. The data model roughly follows the OGC "Simple Features for SQL" specification (see http://www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections).
2
+ This is GeoRuby 1.1.0. It is intended as a holder for data returned from PostGIS and the Spatial Extensions of MySql. The data model roughly follows the OGC "Simple Features for SQL" specification (see http://www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections).
3
3
 
4
4
  ===Available data types
5
5
  The following geometric data types are provided :
@@ -14,18 +14,30 @@ The following geometric data types are provided :
14
14
 
15
15
  They can be in 2D, 3DZ, 3DM, and 4D.
16
16
 
17
+ On top of this an Envelope class is available, to contain the bounding box of a geometry.
18
+
17
19
  ===Input and output
18
20
  These geometries can be input and output in WKB/EWKB/WKT/EWKT format (as well as the related HexWKB and HexEWKB formats). HexEWKB and WKB are the default form under which geometric data is returned respectively from PostGIS and MySql.
19
21
 
22
+ GeoRSS Simple, GeoRSS W3CGeo, GeoRSS GML can also be output. Note that they will not output valid RSS, but just the part strictly concerning the geometry as outlined in http://www.georss.org/1/ . Since the model does not allow multiple geometries, for geometry collections, only the first geometry will be output. Similarly, for polygons, the GeoRSS output will only contain the outer ring. As for W3CGeo output, only points can be output, so the first point of the geometry is chosen. By default the Simple format is output. Envelope can also be output in these formats: The box geometric type is chosen (except for W3CGeo, where the center of the envelope is chose).
23
+
24
+ On top of that, there is now support for KML output. As for GeoRSS, a valid KML file will not be output, but only the geometric data. Options <tt>:id</tt>, <tt>:extrude</tt>, <tt>:tesselate</tt> and <tt>:altitude_mode</tt> can be given. Note that if the <tt>:altitude_mode</tt> option is not passed or set to <tt>clampedToGround</tt>, the altitude data will not be output even if present. Envelopes output a LatLonAltBox instead of a geometry.
25
+
20
26
  ===Installation
21
27
  To install the latest version, just type :
22
28
  gem install GeoRuby
23
29
 
24
30
  ===Changes since the last version
25
- - Correction of the output of the MultiPoint EWKT string to follow the specification, instead of what is shown in the examples (of the specification) and output by PostGIS. For example, the string previously output as MULTIPOINT(123.4 123.5,456.7 678.887) will now be output as MULTIPOINT((123.4 123.5),(456.7 678.887))
26
- - Modification of the EWKT input to support the correct MultiPoint EWKT format, on top of the previous one. So both MULTIPOINT(123.4 123.5,456.7 678.887) and MULTIPOINT((123.4 123.5),(456.7 678.887)) would be accepted as valid MultiPoint strings.
27
- - Addition of a +bounding_box+ method on geometries. Return an array of 2 points representing the 2 corners of the box.
28
- - Geometries that are aggregation of other geometries (line strings, polygons, multi points, multi line strings, multi polygons and geometry collections) can now behave exactly like arrays.
31
+ - Addition of the Vincenty ellipsoidal distance calculation method
32
+ - The spherical distance now assumes the x and y are in degrees not radians
33
+ - Addition of aliases to the +x+ and +y+ accessors, as well as the <tt>from_x_y_...</tt> constructors so the +x+ can be replaced by +lon+ and +y+ by +lat+.
34
+ - Output of GeoRSS Simple, W3CGeo and GML formats
35
+ - Output of KML format
36
+
37
+ ===For version 1.2.0
38
+ - Reading (and writing?) of SHP files
39
+ - Parsing of GeoRSS data
40
+ - Update of the tutorials to show the GeoRSS and KML output, as well as the reading of SHP files
29
41
 
30
42
  ===License
31
43
  GeoRuby is released under the MIT license.
data/lib/geo_ruby.rb CHANGED
@@ -7,6 +7,7 @@ require 'geo_ruby/simple_features/multi_point'
7
7
  require 'geo_ruby/simple_features/multi_line_string'
8
8
  require 'geo_ruby/simple_features/multi_polygon'
9
9
  require 'geo_ruby/simple_features/geometry_collection'
10
+ require 'geo_ruby/simple_features/envelope'
10
11
  require 'geo_ruby/simple_features/ewkb_parser'
11
12
  require 'geo_ruby/simple_features/ewkt_parser'
12
13
  require 'geo_ruby/simple_features/geometry_factory'
@@ -0,0 +1,110 @@
1
+ module GeoRuby
2
+ module SimpleFeatures
3
+
4
+ class Envelope
5
+ attr_accessor :lower_corner, :upper_corner
6
+ attr_accessor :srid, :with_z
7
+
8
+ #Creates a enw Envelope with +lower_corner+ as the first element of the corners array and +upper_corner+ as the second element
9
+ def initialize(corners, srid = DEFAULT_SRID, with_z = false)
10
+ @lower_corner,@upper_corner = corners
11
+ @srid = srid
12
+ @with_z = with_z
13
+ end
14
+
15
+ #Merges the argument with the current evelope
16
+ def extend!(envelope)
17
+ lower_corner.x = [lower_corner.x,envelope.lower_corner.x].min
18
+ lower_corner.y = [lower_corner.y,envelope.lower_corner.y].min
19
+ upper_corner.x = [upper_corner.x,envelope.upper_corner.x].max
20
+ upper_corner.y = [upper_corner.y,envelope.upper_corner.y].max
21
+ self
22
+ end
23
+
24
+ #Merges the argument with the current evelope and sends back a new
25
+ #envelope without changing the current one
26
+ def extend(envelope)
27
+ e = Envelope.new([Point.from_x_y(lower_corner.x,lower_corner.y),
28
+ Point.from_x_y(upper_corner.x,upper_corner.y)])
29
+ e.extend!(envelope)
30
+ e
31
+ end
32
+
33
+ #Sends back the center of the envelope
34
+ def center
35
+ Point.from_x_y((lower_corner.x + upper_corner.x)/2,(lower_corner.y + upper_corner.y)/2)
36
+ end
37
+
38
+ #georss serialization: Dialect can be passed as option <tt>:dialect</tt> and set to <tt>:simple</tt> (default)
39
+ #<tt>:w3cgeo</tt> or <tt>:gml</tt>. Options <tt>:featuretypetag
40
+ def as_georss(options)
41
+ dialect= options[:dialect] || :simple
42
+ case(dialect)
43
+ when :simple
44
+ geom_attr = ""
45
+ geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
46
+ geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
47
+ geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
48
+ geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
49
+ geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
50
+
51
+ georss_simple_representation(options.merge(:geom_attr => geom_attr))
52
+ when :w3cgeo
53
+ georss_w3cgeo_representation(options)
54
+ when :gml
55
+ georss_gml_representation(options)
56
+ end
57
+ end
58
+
59
+ #georss simple representation
60
+ def georss_simple_representation(options) #:nodoc:
61
+ georss_ns = options[:georss_ns] || "georss"
62
+ geom_attr = options[:geom_attr]
63
+ "<#{georss_ns}:box#{geom_attr}>#{lower_corner.y} #{lower_corner.x} #{upper_corner.y} #{upper_corner.x}</#{georss_ns}:box>\n"
64
+ end
65
+
66
+ #georss w3c representation : outputs the first point of the line
67
+ def georss_w3cgeo_representation(options) #:nodoc:
68
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
69
+ point = self.center
70
+ "<#{w3cgeo_ns}:lat>#{point.y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{point.x}</#{w3cgeo_ns}:long>\n"
71
+ end
72
+
73
+ #georss gml representation
74
+ def georss_gml_representation(options) #:nodoc:
75
+ georss_ns = options[:georss_ns] || "georss"
76
+ gml_ns = options[:gml_ns] || "gml"
77
+ result = "<#{georss_ns}:where>\n<#{gml_ns}:Envelope>\n"
78
+ result += "<#{gml_ns}:LowerCorner>" + "#{lower_corner.y} #{lower_corner.x}" + "</#{gml_ns}:LowerCorner>"
79
+ result += "<#{gml_ns}:UpperCorner>" + "#{upper_corner.y} #{upper_corner.x}" + "</#{gml_ns}:UpperCorner>"
80
+ result += "</#{gml_ns}:Envelope>\n</#{georss_ns}:where>\n"
81
+ end
82
+
83
+ #Sends back a latlonaltbox
84
+ def as_kml(options = {})
85
+ geom_data = ""
86
+ geom_data = "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
87
+
88
+ allow_z = with_z && (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
89
+
90
+ kml_representation(options.merge(:geom_data => geom_data,:allow_z => allow_z))
91
+ end
92
+
93
+ def kml_representation(options = {})#:nodoc:
94
+ result = "<LatLonAltBox>\n"
95
+ result += options[:geom_data]
96
+ result += "<north>#{upper_corner.y}</north>\n"
97
+ result += "<south>#{lower_corner.y}</south>\n"
98
+ result += "<east>#{upper_corner.x}</east>\n"
99
+ result += "<west>#{lower_corner.x}</west>\n"
100
+
101
+ if with_z
102
+ result += "<minAltitude>#{lower_corner.z}</minAltitude>"
103
+ result += "<maxAltitude>#{upper_corner.z}</maxAltitude>"
104
+ end
105
+
106
+ result += "</LatLonAltBox>\n"
107
+ end
108
+ end
109
+ end
110
+ end
@@ -25,6 +25,16 @@ module GeoRuby#:nodoc:
25
25
  @with_z=with_z
26
26
  @with_m=with_m
27
27
  end
28
+
29
+
30
+ #to be implemented in subclasses
31
+ def bounding_box
32
+ end
33
+
34
+ #Returns an Envelope object for the geometry
35
+ def envelope
36
+ Envelope.new(bounding_box,srid,with_z)
37
+ end
28
38
 
29
39
  #Outputs the geometry as an EWKB string.
30
40
  #The +allow_srid+, +allow_z+ and +allow_m+ arguments allow the output to include srid, z and m respectively if they are present in the geometry. If these arguments are set to false, srid, z and m are not included, even if they are present in the geometry. By default, the output string contains all the information in the object.
@@ -82,6 +92,43 @@ module GeoRuby#:nodoc:
82
92
  def as_wkt
83
93
  as_ewkt(false,false,false)
84
94
  end
95
+
96
+ #Outputs the geometry in georss format.
97
+ #Assumes the geometries are in latlon format, with x as lon and y as lat.
98
+ def as_georss(options = {})
99
+ dialect= options[:dialect] || :simple
100
+ case(dialect)
101
+ when :simple
102
+ geom_attr = ""
103
+ geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
104
+ geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
105
+ geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
106
+ geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
107
+ geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
108
+ georss_simple_representation(options.merge(:geom_attr => geom_attr))
109
+ when :w3cgeo
110
+ georss_w3cgeo_representation(options)
111
+ when :gml
112
+ georss_gml_representation(options)
113
+ end
114
+ end
115
+
116
+ #Iutputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
117
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
118
+ #it won't be used by GE anyway: clampToGround is the default)
119
+ def as_kml(options = {})
120
+ id_attr = ""
121
+ id_attr = " id=\"#{options[:id]}\"" if options[:id]
122
+
123
+ geom_data = ""
124
+ geom_data += "<extrude>#{options[:extrude]}</extrude>\n" if options[:extrude]
125
+ geom_data += "<tesselate>#{options[:tesselate]}</tesselate>\n" if options[:tesselate]
126
+ geom_data += "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
127
+
128
+ allow_z = with_z && (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
129
+
130
+ kml_representation(options.merge(:id_attr => id_attr, :geom_data => geom_data, :allow_z => allow_z))
131
+ end
85
132
 
86
133
  #Creates a geometry based on a EWKB string. The actual class returned depends of the content of the string passed as argument. Since WKB strings are a subset of EWKB, they are also valid.
87
134
  def self.from_ewkb(ewkb)
@@ -16,19 +16,37 @@ module GeoRuby
16
16
  @geometries.send(method_name,*args,&b)
17
17
  end
18
18
 
19
- #Bounding box in 2D. Returns an array of 2 points
19
+ #Bounding box in 2D/3D. Returns an array of 2 points
20
20
  def bounding_box
21
- max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
22
- each do |geometry|
23
- bbox = geometry.bounding_box
24
- sw = bbox[0]
25
- ne = bbox[1]
26
- max_y = ne.y if ne.y > max_y
27
- min_y = sw.y if sw.y < min_y
28
- max_x = ne.x if ne.x > max_x
29
- min_x = sw.x if sw.x < min_x
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)]
30
49
  end
31
- [Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
32
50
  end
33
51
 
34
52
  #tests the equality of geometry collections
@@ -48,7 +66,7 @@ module GeoRuby
48
66
  end
49
67
 
50
68
  #Binary representation of the collection
51
- def binary_representation(allow_z=true,allow_m=true)
69
+ def binary_representation(allow_z=true,allow_m=true) #:nodoc:
52
70
  rep = [length].pack("V")
53
71
  #output the list of geometries without outputting the SRID first and with the same setting regarding Z and M
54
72
  each {|geometry| rep << geometry.as_ewkb(false,allow_z,allow_m) }
@@ -56,19 +74,42 @@ module GeoRuby
56
74
  end
57
75
 
58
76
  #WKB geometry type of the collection
59
- def binary_geometry_type
77
+ def binary_geometry_type #:nodoc:
60
78
  7
61
79
  end
62
80
 
63
81
  #Text representation of a geometry collection
64
- def text_representation(allow_z=true,allow_m=true)
82
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
65
83
  @geometries.collect{|geometry| geometry.as_ewkt(false,allow_z,allow_m)}.join(",")
66
84
  end
67
85
 
68
86
  #WKT geometry type
69
- def text_geometry_type
87
+ def text_geometry_type #:nodoc:
70
88
  "GEOMETRYCOLLECTION"
71
89
  end
90
+
91
+ #georss simple representation : outputs only the first geometry of the collection
92
+ def georss_simple_representation(options)#:nodoc:
93
+ self[0].georss_simple_representation(options)
94
+ end
95
+ #georss w3c representation : outputs the first point of the outer ring
96
+ def georss_w3cgeo_representation(options)#:nodoc:
97
+ self[0].georss_w3cgeo_representation(options)
98
+ end
99
+ #georss gml representation : outputs only the first geometry of the collection
100
+ def georss_gml_representation(options)#:nodoc:
101
+ self[0].georss_gml_representation(options)
102
+ end
103
+
104
+ #outputs the geometry in kml format
105
+ def kml_representation(options = {}) #:nodoc:
106
+ result = "<MultiGeometry#{options[:id_attr]}>\n"
107
+ options[:id_attr] = "" #the subgeometries do not have an ID
108
+ each do |geometry|
109
+ result += geometry.kml_representation(options)
110
+ end
111
+ result += "</MultiGeometry>\n"
112
+ end
72
113
 
73
114
  #creates a new GeometryCollection from an array of geometries
74
115
  def self.from_geometries(geometries,srid=DEFAULT_SRID,with_z=false,with_m=false)
@@ -23,16 +23,29 @@ module GeoRuby
23
23
  @points.first == @points.last
24
24
  end
25
25
 
26
- #Bounding box in 2D. Returns an array of 2 points
26
+ #Bounding box in 2D/3D. Returns an array of 2 points
27
27
  def bounding_box
28
28
  max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
29
- each do |point|
30
- max_y = point.y if point.y > max_y
31
- min_y = point.y if point.y < min_y
32
- max_x = point.x if point.x > max_x
33
- min_x = point.x if point.x < min_x
29
+ if(with_z)
30
+ max_z, min_z = -Float::MAX,Float::MAX
31
+ each do |point|
32
+ max_y = point.y if point.y > max_y
33
+ min_y = point.y if point.y < min_y
34
+ max_x = point.x if point.x > max_x
35
+ min_x = point.x if point.x < min_x
36
+ max_z = point.z if point.z > max_z
37
+ min_z = point.z if point.z < min_z
38
+ end
39
+ [Point.from_x_y_z(min_x,min_y,min_z),Point.from_x_y_z(max_x,max_y,max_z)]
40
+ else
41
+ each do |point|
42
+ max_y = point.y if point.y > max_y
43
+ min_y = point.y if point.y < min_y
44
+ max_x = point.x if point.x > max_x
45
+ min_x = point.x if point.x < min_x
46
+ end
47
+ [Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
34
48
  end
35
- [Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
36
49
  end
37
50
 
38
51
  #Tests the equality of line strings
@@ -51,25 +64,70 @@ module GeoRuby
51
64
  end
52
65
 
53
66
  #Binary representation of a line string
54
- def binary_representation(allow_z=true,allow_m=true)
67
+ def binary_representation(allow_z=true,allow_m=true) #:nodoc:
55
68
  rep = [length].pack("V")
56
69
  each {|point| rep << point.binary_representation(allow_z,allow_m) }
57
70
  rep
58
71
  end
59
72
 
60
73
  #WKB geometry type
61
- def binary_geometry_type
74
+ def binary_geometry_type #:nodoc:
62
75
  2
63
76
  end
64
77
 
65
78
  #Text representation of a line string
66
- def text_representation(allow_z=true,allow_m=true)
79
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
67
80
  @points.collect{|point| point.text_representation(allow_z,allow_m) }.join(",")
68
81
  end
69
82
  #WKT geometry type
70
- def text_geometry_type
83
+ def text_geometry_type #:nodoc:
71
84
  "LINESTRING"
72
85
  end
86
+
87
+ #georss simple representation
88
+ def georss_simple_representation(options) #:nodoc:
89
+ georss_ns = options[:georss_ns] || "georss"
90
+ geom_attr = options[:geom_attr]
91
+ "<#{georss_ns}:line#{geom_attr}>" + georss_poslist + "</#{georss_ns}:line>\n"
92
+ end
93
+ #georss w3c representation : outputs the first point of the line
94
+ def georss_w3cgeo_representation(options) #:nodoc:
95
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
96
+ "<#{w3cgeo_ns}:lat>#{self[0].y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{self[0].x}</#{w3cgeo_ns}:long>\n"
97
+ end
98
+ #georss gml representation
99
+ def georss_gml_representation(options) #:nodoc:
100
+ georss_ns = options[:georss_ns] || "georss"
101
+ gml_ns = options[:gml_ns] || "gml"
102
+
103
+ result = "<#{georss_ns}:where>\n<#{gml_ns}:LineString>\n<#{gml_ns}:posList>\n"
104
+ result += georss_poslist
105
+ result += "\n</#{gml_ns}:posList>\n</#{gml_ns}:LineString>\n</#{georss_ns}:where>\n"
106
+ end
107
+
108
+ def georss_poslist #:nodoc:
109
+ map {|point| "#{point.y} #{point.x}"}.join(" ")
110
+ end
111
+
112
+ #outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
113
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
114
+ #it won't be used by GE anyway: clampToGround is the default)
115
+ def kml_representation(options = {}) #:nodoc:
116
+ result = "<LineString#{options[:id_attr]}>\n"
117
+ result += options[:geom_data]
118
+ result += "<coordinates>"
119
+ result += kml_poslist(options[:allow_z])
120
+ result += "</coordinates>\n"
121
+ result += "</LineString>\n"
122
+ end
123
+
124
+ def kml_poslist(allow_z) #:nodoc:
125
+ if allow_z
126
+ map {|point| "#{point.x},#{point.y},#{point.z || 0}" }.join(" ")
127
+ else
128
+ map {|point| "#{point.x},#{point.y}" }.join(" ")
129
+ end
130
+ end
73
131
 
74
132
  #Creates a new line string. Accept an array of points as argument
75
133
  def self.from_points(points,srid=DEFAULT_SRID,with_z=false,with_m=false)
@@ -7,16 +7,17 @@ module GeoRuby
7
7
  def initialize(srid = DEFAULT_SRID,with_z=false,with_m=false)
8
8
  super(srid)
9
9
  end
10
- def binary_geometry_type
10
+
11
+ def binary_geometry_type #:nodoc:
11
12
  5
12
13
  end
13
14
 
14
15
  #Text representation of a multi line string
15
- def text_representation(allow_z=true,allow_m=true)
16
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
16
17
  @geometries.collect{|line_string| "(" + line_string.text_representation(allow_z,allow_m) + ")" }.join(",")
17
18
  end
18
19
  #WKT geometry type
19
- def text_geometry_type
20
+ def text_geometry_type #:nodoc:
20
21
  "MULTILINESTRING"
21
22
  end
22
23
 
@@ -9,16 +9,16 @@ module GeoRuby
9
9
  super(srid,with_z,with_m)
10
10
  end
11
11
 
12
- def binary_geometry_type
12
+ def binary_geometry_type #:nodoc:
13
13
  4
14
14
  end
15
15
 
16
16
  #Text representation of a MultiPoint
17
- def text_representation(allow_z=true,allow_m=true)
17
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
18
18
  "(" + @geometries.collect{|point| point.text_representation(allow_z,allow_m)}.join("),(") + ")"
19
19
  end
20
20
  #WKT geoemtry type
21
- def text_geometry_type
21
+ def text_geometry_type #:nodoc:
22
22
  "MULTIPOINT"
23
23
  end
24
24
 
@@ -8,15 +8,16 @@ module GeoRuby
8
8
  def initialize(srid = DEFAULT_SRID,with_z=false,with_m=false)
9
9
  super(srid)
10
10
  end
11
- def binary_geometry_type
11
+
12
+ def binary_geometry_type #:nodoc:
12
13
  6
13
14
  end
14
15
  #Text representation of a MultiPolygon
15
- def text_representation(allow_z=true,allow_m=true)
16
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
16
17
  @geometries.collect{|polygon| "(" + polygon.text_representation(allow_z,allow_m) + ")"}.join(",")
17
18
  end
18
19
  #WKT geometry type
19
- def text_geometry_type
20
+ def text_geometry_type #:nodoc:
20
21
  "MULTIPOLYGON"
21
22
  end
22
23
 
@@ -5,7 +5,11 @@ module GeoRuby
5
5
  #Represents a point. It is in 3D if the Z coordinate is not +nil+.
6
6
  class Point < Geometry
7
7
 
8
+
8
9
  attr_accessor :x,:y,:z,:m
10
+ #if you prefer calling the coordinates lat and lon
11
+ alias :lon :x
12
+ alias :lat :y
9
13
 
10
14
  def initialize(srid=DEFAULT_SRID,with_z=false,with_m=false)
11
15
  super(srid,with_z,with_m)
@@ -20,34 +24,93 @@ module GeoRuby
20
24
  @y=y
21
25
  @z=z
22
26
  end
27
+ alias :set_lon_lat_z :set_x_y_z
28
+
23
29
  #sets all coordinates of a 2D point in one call
24
30
  def set_x_y(x,y)
25
31
  @x=x
26
32
  @y=y
27
33
  end
34
+ alias :set_lon_lat :set_x_y
28
35
 
29
36
  #Return the distance between the 2D points (ie taking care only of the x and y coordinates), assuming the points are in projected coordinates. Euclidian distance in whatever unit the x and y ordinates are.
30
37
  def euclidian_distance(point)
31
38
  Math.sqrt((point.x - x)**2 + (point.y - y)**2)
32
39
  end
33
40
 
34
- #Returns the sperical distance, with a radius of 6471000m, with the haversine law. Assumes x is the lon and y the lat, in radians. Returns the distance in meters by default, although by passing a value to the radius argument, this can be changed.
35
- def spherical_distance(point,radius=6371000)
36
- dlat = point.y - y
37
- dlon = point.x - x
38
- a = Math.sin(dlat/2)**2 + Math.cos(point.y) * Math.cos(y) * (Math.sin(dlon/2)**2)
41
+ #Returns the sperical distance in m, with a radius of 6471000m, with the haversine law. Assumes x is the lon and y the lat, in degrees (Changed in version 1.1). The user has to make sure using this distance makes sense (ie she should be in latlon coordinates)
42
+ def spherical_distance(point,radius=6370997.0)
43
+ deg_to_rad = 0.0174532925199433
44
+
45
+ radlat_from = lat * deg_to_rad
46
+ radlat_to = point.lat * deg_to_rad
47
+
48
+ dlat = (point.lat - lat) * deg_to_rad
49
+ dlon = (point.lon - lon) * deg_to_rad
50
+
51
+ a = Math.sin(dlat/2)**2 + Math.cos(radlat_from) * Math.cos(radlat_to) * Math.sin(dlon/2)**2
39
52
  c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
40
53
  radius * c
41
54
  end
42
55
 
43
- #Ellipsoidal distance? Not implemented yet. Complicated and don't feel like it today. Check out http://www.movable-type.co.uk/scripts/LatLongVincenty.html for more info. I accept patches...
44
- def ellipsoidal_distance(point)
45
- end
46
-
56
+ #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.
57
+ #a is the semi-major axis (equatorial radius) of the ellipsoid
58
+ #b is the semi-minor axis (polar radius) of the ellipsoid
59
+ #Their values by default are set to the ones of the WGS84 ellipsoid
60
+ def ellipsoidal_distance(point, a = 6378137.0, b = 6356752.3142)
61
+ deg_to_rad = 0.0174532925199433
62
+
63
+ f = (a-b) / a
64
+ l = (point.lon - lon) * deg_to_rad
65
+
66
+ u1 = Math.atan((1-f) * Math.tan(lat * deg_to_rad ))
67
+ u2 = Math.atan((1-f) * Math.tan(point.lat * deg_to_rad))
68
+ sinU1 = Math.sin(u1)
69
+ cosU1 = Math.cos(u1)
70
+ sinU2 = Math.sin(u2)
71
+ cosU2 = Math.cos(u2)
72
+
73
+ lambda = l
74
+ lambdaP = 2 * Math::PI
75
+ iterLimit = 20
76
+
77
+ while (lambda-lambdaP).abs > 1e-12 && --iterLimit>0
78
+ sinLambda = Math.sin(lambda)
79
+ cosLambda = Math.cos(lambda)
80
+ sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda))
81
+
82
+ return 0 if sinSigma == 0 #coincident points
83
+
84
+ cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda
85
+ sigma = Math.atan2(sinSigma, cosSigma)
86
+ sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma
87
+ cosSqAlpha = 1 - sinAlpha*sinAlpha
88
+ cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha
89
+
90
+ cos2SigmaM = 0 if (cos2SigmaM.nan?) #equatorial line: cosSqAlpha=0
91
+
92
+ c = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha))
93
+ lambdaP = lambda
94
+ lambda = l + (1-c) * f * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)))
95
+ end
96
+ return NaN if iterLimit==0 #formula failed to converge
97
+
98
+ uSq = cosSqAlpha * (a*a - b*b) / (b*b)
99
+ a_bis = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
100
+ b_bis = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
101
+ 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)))
47
102
 
48
- #Bounding box in 2D. Returns an array of 2 points
103
+ b*a_bis*(sigma-deltaSigma)
104
+ end
105
+
106
+
107
+ #Bounding box in 2D/3D. Returns an array of 2 points
49
108
  def bounding_box
50
- [Point.from_x_y(@x,@y),Point.from_x_y(@x,@y)] #not too difficult...
109
+ unless with_z
110
+ [Point.from_x_y(@x,@y),Point.from_x_y(@x,@y)]
111
+ else
112
+ [Point.from_x_y_z(@x,@y,@z),Point.from_x_y_z(@x,@y,@z)]
113
+ end
51
114
  end
52
115
 
53
116
  #tests the equality of the position of points + m
@@ -58,29 +121,62 @@ module GeoRuby
58
121
  @x == other_point.x and @y == other_point.y and @z == other_point.z and @m == other_point.m
59
122
  end
60
123
  end
124
+
61
125
  #binary representation of a point. It lacks some headers to be a valid EWKB representation.
62
- def binary_representation(allow_z=true,allow_m=true)
126
+ def binary_representation(allow_z=true,allow_m=true) #:nodoc:
63
127
  bin_rep = [@x,@y].pack("EE")
64
128
  bin_rep += [@z].pack("E") if @with_z and allow_z #Default value so no crash
65
129
  bin_rep += [@m].pack("E") if @with_m and allow_m #idem
66
130
  bin_rep
67
131
  end
68
132
  #WKB geometry type of a point
69
- def binary_geometry_type
133
+ def binary_geometry_type#:nodoc:
70
134
  1
71
135
  end
72
136
 
73
137
  #text representation of a point
74
- def text_representation(allow_z=true,allow_m=true)
138
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
75
139
  tex_rep = "#{@x} #{@y}"
76
140
  tex_rep += " #{@z}" if @with_z and allow_z
77
141
  tex_rep += " #{@m}" if @with_m and allow_m
78
142
  tex_rep
79
143
  end
80
144
  #WKT geometry type of a point
81
- def text_geometry_type
145
+ def text_geometry_type #:nodoc:
82
146
  "POINT"
83
147
  end
148
+
149
+ #georss simple representation
150
+ def georss_simple_representation(options) #:nodoc:
151
+ georss_ns = options[:georss_ns] || "georss"
152
+ geom_attr = options[:geom_attr]
153
+ "<#{georss_ns}:point#{geom_attr}>#{y} #{x}</#{georss_ns}:point>\n"
154
+ end
155
+ #georss w3c representation
156
+ def georss_w3cgeo_representation(options) #:nodoc:
157
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
158
+ "<#{w3cgeo_ns}:lat>#{y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{x}</#{w3cgeo_ns}:long>\n"
159
+ end
160
+ #georss gml representation
161
+ def georss_gml_representation(options) #:nodoc:
162
+ georss_ns = options[:georss_ns] || "georss"
163
+ gml_ns = options[:gml_ns] || "gml"
164
+ result = "<#{georss_ns}:where>\n<#{gml_ns}:Point>\n<#{gml_ns}:pos>"
165
+ result += "#{y} #{x}"
166
+ result += "</#{gml_ns}:pos>\n</#{gml_ns}:Point>\n</#{georss_ns}:where>\n"
167
+ end
168
+
169
+ #outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
170
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
171
+ #it won't be used by GE anyway: clampToGround is the default)
172
+ def kml_representation(options = {}) #:nodoc:
173
+ result = "<Point#{options[:id_attr]}>\n"
174
+ result += options[:geom_data]
175
+ result += "<coordinates>#{x},#{y}"
176
+ result += ",#{z || 0}" if options[:allow_z]
177
+ result += "</coordinates>\n"
178
+ result += "</Point>\n"
179
+ end
84
180
 
85
181
  #creates a point from an array of coordinates
86
182
  def self.from_coordinates(coords,srid=DEFAULT_SRID,with_z=false,with_m=false)
@@ -94,18 +190,22 @@ module GeoRuby
94
190
  from_x_y_m(coords[0],coords[1],coords[2],srid)
95
191
  end
96
192
  end
193
+
97
194
  #creates a point from the X and Y coordinates
98
195
  def self.from_x_y(x,y,srid=DEFAULT_SRID)
99
196
  point= Point::new(srid)
100
197
  point.set_x_y(x,y)
101
198
  point
102
199
  end
200
+
103
201
  #creates a point from the X, Y and Z coordinates
104
202
  def self.from_x_y_z(x,y,z,srid=DEFAULT_SRID)
105
203
  point= Point::new(srid,true)
106
204
  point.set_x_y_z(x,y,z)
107
205
  point
108
206
  end
207
+
208
+
109
209
  #creates a point from the X, Y and M coordinates
110
210
  def self.from_x_y_m(x,y,m,srid=DEFAULT_SRID)
111
211
  point= Point::new(srid,false,true)
@@ -113,6 +213,7 @@ module GeoRuby
113
213
  point.m=m
114
214
  point
115
215
  end
216
+
116
217
  #creates a point from the X, Y, Z and M coordinates
117
218
  def self.from_x_y_z_m(x,y,z,m,srid=DEFAULT_SRID)
118
219
  point= Point::new(srid,true,true)
@@ -120,6 +221,14 @@ module GeoRuby
120
221
  point.m=m
121
222
  point
122
223
  end
224
+
225
+ #aliasing the constructors in case you want to use lat/lon instead of y/x
226
+ class << self
227
+ alias :from_lon_lat :from_x_y
228
+ alias :from_lon_lat_z :from_x_y_z
229
+ alias :from_lon_lat_m :from_x_y_m
230
+ alias :from_lon_lat_z_m :from_x_y_z_m
231
+ end
123
232
  end
124
233
  end
125
234
  end
@@ -17,9 +17,23 @@ module GeoRuby
17
17
  @rings.send(method_name,*args,&b)
18
18
  end
19
19
 
20
- #Bounding box in 2D. Returns an array of 2 points
20
+ #Bounding box in 2D/3D. Returns an array of 2 points
21
21
  def bounding_box
22
- @rings[0].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
23
37
  end
24
38
 
25
39
  #tests for other equality. The SRID is not taken into account.
@@ -56,6 +70,45 @@ module GeoRuby
56
70
  "POLYGON"
57
71
  end
58
72
 
73
+ #georss simple representation : outputs only the outer ring
74
+ def georss_simple_representation(options)
75
+ georss_ns = options[:georss_ns] || "georss"
76
+ geom_attr = options[:geom_attr]
77
+ "<#{georss_ns}:polygon#{geom_attr}>" + self[0].georss_poslist + "</#{georss_ns}:polygon>\n"
78
+ end
79
+ #georss w3c representation : outputs the first point of the outer ring
80
+ def georss_w3cgeo_representation(options)
81
+ w3cgeo_ns = options[:w3cgeo_ns] || "geo"
82
+
83
+ "<#{w3cgeo_ns}:lat>#{self[0][0].y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{self[0][0].x}</#{w3cgeo_ns}:long>\n"
84
+ end
85
+ #georss gml representation
86
+ def georss_gml_representation(options)
87
+ georss_ns = options[:georss_ns] || "georss"
88
+ gml_ns = options[:gml_ns] || "gml"
89
+
90
+ 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"
91
+ end
92
+
93
+ #outputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
94
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
95
+ #it won't be used by GE anyway: clampToGround is the default)
96
+ def kml_representation(options = {})
97
+ result = "<Polygon#{options[:id_attr]}>\n"
98
+ result += options[:geom_data]
99
+ rings.each_with_index do |ring, i|
100
+ if i == 0
101
+ boundary = "outerBoundaryIs"
102
+ else
103
+ boundary = "innerBoundaryIs"
104
+ end
105
+ result += "<#{boundary}><LinearRing><coordinates>\n"
106
+ result += ring.kml_poslist(options[:allow_z])
107
+ result += "\n</coordinates></LinearRing></#{boundary}>\n"
108
+ end
109
+ result += "</Polygon>\n"
110
+ end
111
+
59
112
  #creates a new polygon. Accepts an array of linear strings as argument
60
113
  def self.from_linear_rings(linear_rings,srid = DEFAULT_SRID,with_z=false,with_m=false)
61
114
  polygon = Polygon::new(srid,with_z,with_m)
@@ -70,7 +123,6 @@ module GeoRuby
70
123
  polygon
71
124
  end
72
125
 
73
-
74
126
  end
75
127
  end
76
128
  end
data/rakefile.rb CHANGED
@@ -24,14 +24,14 @@ spec = Gem::Specification::new do |s|
24
24
  s.platform = Gem::Platform::RUBY
25
25
 
26
26
  s.name = 'GeoRuby'
27
- s.version = "1.0.0"
27
+ s.version = "1.1.0"
28
28
  s.summary = "Ruby data holder for OGC Simple Features"
29
29
  s.description = <<EOF
30
30
  GeoRuby is intended as a holder for data returned from PostGIS and MySQL Spatial queries. The data model roughly follows the OGC "Simple Features for SQL" specification (see www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections)
31
31
  EOF
32
32
  s.author = 'Guilhem Vellut'
33
33
  s.email = 'guilhem.vellut+georuby@gmail.com'
34
- s.homepage = "http://thepochisuperstarmegashow.com"
34
+ s.homepage = "http://thepochisuperstarmegashow.com/projects"
35
35
 
36
36
  s.requirements << 'none'
37
37
  s.require_path = 'lib'
@@ -0,0 +1,68 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'geo_ruby'
4
+ require 'test/unit'
5
+
6
+ include GeoRuby::SimpleFeatures
7
+
8
+ class TestGeorssKml < Test::Unit::TestCase
9
+
10
+ def test_geometry_creation
11
+ point = Point.from_x_y(3,4)
12
+
13
+ assert_equal("<georss:point featuretypetag=\"hoyoyo\" elev=\"45.7\">4 3</georss:point>", point.as_georss(:dialect => :simple, :elev => 45.7, :featuretypetag => "hoyoyo").gsub("\n",""))
14
+ assert_equal("<geo:lat>4</geo:lat><geo:long>3</geo:long>",point.as_georss(:dialect => :w3cgeo).gsub("\n",""))
15
+ assert_equal("<georss:where><gml:Point><gml:pos>4 3</gml:pos></gml:Point></georss:where>",point.as_georss(:dialect => :gml).gsub("\n",""))
16
+
17
+ assert_equal("<Point id=\"HOYOYO-42\"><coordinates>3,4</coordinates></Point>",point.as_kml(:id => "HOYOYO-42").gsub("\n",""))
18
+ end
19
+
20
+ def test_line_string
21
+ ls = LineString.from_points([Point.from_lon_lat_z(12.4,-45.3,56),Point.from_lon_lat_z(45.4,41.6,45)],123,true)
22
+
23
+ assert_equal("<georss:line>-45.3 12.4 41.6 45.4</georss:line>",ls.as_georss.gsub("\n",""))
24
+ assert_equal("<geo:lat>-45.3</geo:lat><geo:long>12.4</geo:long>",ls.as_georss(:dialect => :w3cgeo).gsub("\n",""))
25
+ assert_equal("<georss:where><gml:LineString><gml:posList>-45.3 12.4 41.6 45.4</gml:posList></gml:LineString></georss:where>",ls.as_georss(:dialect => :gml).gsub("\n",""))
26
+
27
+ assert_equal("<LineString><extrude>1</extrude><altitudeMode>absolute</altitudeMode><coordinates>12.4,-45.3,56 45.4,41.6,45</coordinates></LineString>",ls.as_kml(:extrude => 1, :altitude_mode => "absolute").gsub("\n",""))
28
+ end
29
+
30
+ def test_polygon
31
+ linear_ring1 = LinearRing.from_coordinates([[12.4,-45.3],[45.4,41.6],[4.456,1.0698],[12.4,-45.3]],256)
32
+ linear_ring2 = LinearRing.from_coordinates([[2.4,5.3],[5.4,1.4263],[14.46,1.06],[2.4,5.3]],256)
33
+ polygon = Polygon.from_linear_rings([linear_ring1,linear_ring2],256)
34
+
35
+ assert_equal("<hoyoyo:polygon>-45.3 12.4 41.6 45.4 1.0698 4.456 -45.3 12.4</hoyoyo:polygon>",polygon.as_georss(:georss_ns => "hoyoyo").gsub("\n",""))
36
+ assert_equal("<bouyoul:lat>-45.3</bouyoul:lat><bouyoul:long>12.4</bouyoul:long>",polygon.as_georss(:dialect => :w3cgeo, :w3cgeo_ns => "bouyoul").gsub("\n",""))
37
+ assert_equal("<georss:where><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>-45.3 12.4 41.6 45.4 1.0698 4.456 -45.3 12.4</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></georss:where>",polygon.as_georss(:dialect => :gml).gsub("\n",""))
38
+
39
+ assert_equal("<Polygon><outerBoundaryIs><LinearRing><coordinates>12.4,-45.3 45.4,41.6 4.456,1.0698 12.4,-45.3</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><coordinates>2.4,5.3 5.4,1.4263 14.46,1.06 2.4,5.3</coordinates></LinearRing></innerBoundaryIs></Polygon>",polygon.as_kml.gsub("\n",""))
40
+ end
41
+
42
+ def test_geometry_collection
43
+ gc = GeometryCollection.from_geometries([Point.from_x_y(4.67,45.4,256),LineString.from_coordinates([[5.7,12.45],[67.55,54]],256)],256)
44
+
45
+ #only the first geometry is output
46
+ assert_equal("<georss:point floor=\"4\">45.4 4.67</georss:point>",gc.as_georss(:dialect => :simple,:floor => 4).gsub("\n",""))
47
+ assert_equal("<geo:lat>45.4</geo:lat><geo:long>4.67</geo:long>",gc.as_georss(:dialect => :w3cgeo).gsub("\n",""))
48
+ assert_equal("<georss:where><gml:Point><gml:pos>45.4 4.67</gml:pos></gml:Point></georss:where>",gc.as_georss(:dialect => :gml).gsub("\n",""))
49
+
50
+ assert_equal("<MultiGeometry id=\"HOYOYO-42\"><Point><coordinates>4.67,45.4</coordinates></Point><LineString><coordinates>5.7,12.45 67.55,54</coordinates></LineString></MultiGeometry>",gc.as_kml(:id => "HOYOYO-42").gsub("\n",""))
51
+ end
52
+
53
+ def test_envelope
54
+ linear_ring1 = LinearRing.from_coordinates([[12.4,-45.3,5],[45.4,41.6,6],[4.456,1.0698,8],[12.4,-45.3,3.5]],256,true)
55
+ linear_ring2 = LinearRing.from_coordinates([[2.4,5.3,9.0],[5.4,1.4263,-5.4],[14.46,1.06,34],[2.4,5.3,3.14]],256,true)
56
+ polygon = Polygon.from_linear_rings([linear_ring1,linear_ring2],256,true)
57
+
58
+ e = polygon.envelope
59
+
60
+ assert_equal("<georss:box>-45.3 4.456 41.6 45.4</georss:box>",e.as_georss(:dialect => :simple).gsub("\n",""))
61
+ #center
62
+ assert_equal("<geo:lat>-1.85</geo:lat><geo:long>24.928</geo:long>",e.as_georss(:dialect => :w3cgeo).gsub("\n",""))
63
+ assert_equal("<georss:where><gml:Envelope><gml:LowerCorner>-45.3 4.456</gml:LowerCorner><gml:UpperCorner>41.6 45.4</gml:UpperCorner></gml:Envelope></georss:where>",e.as_georss(:dialect => :gml).gsub("\n",""))
64
+
65
+ assert_equal("<LatLonAltBox><north>41.6</north><south>-45.3</south><east>45.4</east><west>4.456</west><minAltitude>-5.4</minAltitude><maxAltitude>34</maxAltitude></LatLonAltBox>",e.as_kml.gsub("\n",""))
66
+ end
67
+
68
+ end
@@ -85,8 +85,8 @@ class TestSimpleFeatures < Test::Unit::TestCase
85
85
 
86
86
  bbox = Point.from_x_y_z_m(-1.6,2.8,-3.4,15,123).bounding_box
87
87
  assert_equal(2,bbox.length)
88
- assert_equal(Point.from_x_y(-1.6,2.8),bbox[0])
89
- assert_equal(Point.from_x_y(-1.6,2.8),bbox[1])
88
+ assert_equal(Point.from_x_y_z(-1.6,2.8,-3.4),bbox[0])
89
+ assert_equal(Point.from_x_y_z(-1.6,2.8,-3.4),bbox[1])
90
90
  end
91
91
 
92
92
  def test_point_equal
@@ -140,10 +140,11 @@ class TestSimpleFeatures < Test::Unit::TestCase
140
140
  def test_point_distance
141
141
  point1 = Point.from_x_y(0,0)
142
142
  point2 = Point.from_x_y(3,4)
143
- assert_equal(point1.euclidian_distance(point2),5)
144
-
145
- point2 = Point.from_x_y(Math::PI,0)
146
- assert_in_delta(point1.spherical_distance(point2),20015086,1)
143
+ assert_equal(5,point1.euclidian_distance(point2))
144
+
145
+ assert_in_delta(554058.924,point1.ellipsoidal_distance(point2),0.001)
146
+
147
+ assert_in_delta(555811.68,point1.spherical_distance(point2),0.01)
147
148
 
148
149
 
149
150
  end
@@ -192,8 +193,8 @@ class TestSimpleFeatures < Test::Unit::TestCase
192
193
 
193
194
  bbox = LineString.from_coordinates([[12.4,-45.3,123],[45.4,41.6,333],[4.456,1.0698,987]],123,true).bounding_box
194
195
  assert_equal(2,bbox.length)
195
- assert_equal(Point.from_x_y(4.456,-45.3),bbox[0])
196
- assert_equal(Point.from_x_y(45.4,41.6),bbox[1])
196
+ assert_equal(Point.from_x_y_z(4.456,-45.3,123),bbox[0])
197
+ assert_equal(Point.from_x_y_z(45.4,41.6,987),bbox[1])
197
198
 
198
199
  end
199
200
 
@@ -283,8 +284,8 @@ class TestSimpleFeatures < Test::Unit::TestCase
283
284
 
284
285
  bbox = Polygon.from_coordinates([[[12.4,-45.3,15.2],[45.4,41.6,2.4],[4.456,1.0698,5.6],[12.4,-45.3,6.1]],[[2.4,5.3,4.5],[5.4,1.4263,4.2],[14.46,1.06,123.1],[2.4,5.3,4.4]]],256,true).bounding_box
285
286
  assert_equal(2,bbox.length)
286
- assert_equal(Point.from_x_y(4.456,-45.3),bbox[0])
287
- assert_equal(Point.from_x_y(45.4,41.6),bbox[1])
287
+ assert_equal(Point.from_x_y_z(4.456,-45.3,2.4),bbox[0])
288
+ assert_equal(Point.from_x_y_z(45.4,41.6,123.1),bbox[1])
288
289
 
289
290
  end
290
291
  def test_polygon_equal
@@ -461,4 +462,27 @@ class TestSimpleFeatures < Test::Unit::TestCase
461
462
 
462
463
  end
463
464
 
465
+ def test_envelope
466
+ linear_ring = LinearRing.from_coordinates([[12.4,-45.3],[45.4,41.6],[4.456,1.0698],[12.4,-45.3]],256)
467
+ polygon = Polygon.from_linear_rings([linear_ring],256)
468
+ e = polygon.envelope
469
+
470
+ assert_equal(e.lower_corner.class, Point)
471
+ assert_equal(e.upper_corner.class, Point)
472
+
473
+ assert_equal(e.lower_corner.x,4.456)
474
+ assert_equal(e.lower_corner.y,-45.3)
475
+ assert_equal(e.upper_corner.x,45.4)
476
+ assert_equal(e.upper_corner.y,41.6)
477
+
478
+ line_string = LineString.from_coordinates([[13.6,-49.3],[45.4,44.6],[14.2,1.09],[13.6,-49.3]],256)
479
+ e2 = line_string.envelope
480
+
481
+ e3 = e.extend(e2)
482
+
483
+ assert_equal(e3.lower_corner.x,4.456)
484
+ assert_equal(e3.lower_corner.y,-49.3)
485
+ assert_equal(e3.upper_corner.x,45.4)
486
+ assert_equal(e3.upper_corner.y,44.6)
487
+ end
464
488
  end
metadata CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: GeoRuby
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.0
7
- date: 2006-08-23 00:00:00 +01:00
6
+ version: 1.1.0
7
+ date: 2006-12-31 00:00:00 +01:00
8
8
  summary: Ruby data holder for OGC Simple Features
9
9
  require_paths:
10
10
  - lib
11
11
  email: guilhem.vellut+georuby@gmail.com
12
- homepage: http://thepochisuperstarmegashow.com
12
+ homepage: http://thepochisuperstarmegashow.com/projects
13
13
  rubyforge_project:
14
14
  description: GeoRuby is intended as a holder for data returned from PostGIS and MySQL Spatial queries. The data model roughly follows the OGC "Simple Features for SQL" specification (see www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections)
15
15
  autorequire:
@@ -30,6 +30,7 @@ authors:
30
30
  - Guilhem Vellut
31
31
  files:
32
32
  - lib/geo_ruby.rb
33
+ - lib/geo_ruby/simple_features/envelope.rb
33
34
  - lib/geo_ruby/simple_features/ewkb_parser.rb
34
35
  - lib/geo_ruby/simple_features/ewkt_parser.rb
35
36
  - lib/geo_ruby/simple_features/geometry.rb
@@ -44,6 +45,7 @@ files:
44
45
  - lib/geo_ruby/simple_features/polygon.rb
45
46
  - test/test_ewkb_parser.rb
46
47
  - test/test_ewkt_parser.rb
48
+ - test/test_georss_kml.rb
47
49
  - test/test_simple_features.rb
48
50
  - README
49
51
  - MIT-LICENSE
@@ -51,6 +53,7 @@ files:
51
53
  test_files:
52
54
  - test/test_ewkb_parser.rb
53
55
  - test/test_ewkt_parser.rb
56
+ - test/test_georss_kml.rb
54
57
  - test/test_simple_features.rb
55
58
  rdoc_options:
56
59
  - --main