GeoRuby 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -19,7 +19,7 @@ On top of this an Envelope class is available, to contain the bounding box of a
19
19
  ===Input and output
20
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.
21
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).
22
+ GeoRSS Simple, GeoRSS W3CGeo, GeoRSS GML can also be input and 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
23
 
24
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
25
 
@@ -28,6 +28,7 @@ To install the latest version, just type :
28
28
  gem install GeoRuby
29
29
 
30
30
  ===Changes since the last version
31
+ - Input of GeoRSS geometries (1.1.1)
31
32
  - Addition of the Vincenty ellipsoidal distance calculation method
32
33
  - The spherical distance now assumes the x and y are in degrees not radians
33
34
  - 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+.
@@ -36,7 +37,7 @@ To install the latest version, just type :
36
37
 
37
38
  ===For version 1.2.0
38
39
  - Reading (and writing?) of SHP files
39
- - Parsing of GeoRSS data
40
+ - Documentation
40
41
  - Update of the tutorials to show the GeoRSS and KML output, as well as the reading of SHP files
41
42
 
42
43
  ===License
data/lib/geo_ruby.rb CHANGED
@@ -11,4 +11,5 @@ require 'geo_ruby/simple_features/envelope'
11
11
  require 'geo_ruby/simple_features/ewkb_parser'
12
12
  require 'geo_ruby/simple_features/ewkt_parser'
13
13
  require 'geo_ruby/simple_features/geometry_factory'
14
+ require 'geo_ruby/simple_features/georss_parser'
14
15
 
@@ -1,13 +1,13 @@
1
1
  module GeoRuby
2
2
  module SimpleFeatures
3
3
 
4
+ #Contains the bounding box of a geometry
4
5
  class Envelope
5
6
  attr_accessor :lower_corner, :upper_corner
6
7
  attr_accessor :srid, :with_z
7
8
 
8
9
  #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
10
+ def initialize(srid = DEFAULT_SRID, with_z = false)
11
11
  @srid = srid
12
12
  @with_z = with_z
13
13
  end
@@ -24,8 +24,8 @@ module GeoRuby
24
24
  #Merges the argument with the current evelope and sends back a new
25
25
  #envelope without changing the current one
26
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)])
27
+ e = Envelope.from_points([Point.from_x_y(lower_corner.x,lower_corner.y),
28
+ Point.from_x_y(upper_corner.x,upper_corner.y)],srid,with_z)
29
29
  e.extend!(envelope)
30
30
  e
31
31
  end
@@ -35,6 +35,15 @@ module GeoRuby
35
35
  Point.from_x_y((lower_corner.x + upper_corner.x)/2,(lower_corner.y + upper_corner.y)/2)
36
36
  end
37
37
 
38
+ #Tests the equality of line strings
39
+ def ==(other_envelope)
40
+ if other_envelope.class != self.class
41
+ false
42
+ else
43
+ upper_corner == other_envelope.upper_corner and lower_corner == other_envelope.lower_corner
44
+ end
45
+ end
46
+
38
47
  #georss serialization: Dialect can be passed as option <tt>:dialect</tt> and set to <tt>:simple</tt> (default)
39
48
  #<tt>:w3cgeo</tt> or <tt>:gml</tt>. Options <tt>:featuretypetag
40
49
  def as_georss(options)
@@ -105,6 +114,21 @@ module GeoRuby
105
114
 
106
115
  result += "</LatLonAltBox>\n"
107
116
  end
117
+
118
+ #Creates a new envelope. Accept an array of 2 points as argument
119
+ def self.from_points(points,srid=DEFAULT_SRID,with_z=false)
120
+ e = Envelope.new(srid,with_z)
121
+ e.lower_corner, e.upper_corner = points
122
+ e
123
+ end
124
+
125
+ #Creates a new envelope. Accept a sequence of points as argument : ((x,y),(x,y))
126
+ def self.from_coordinates(points,srid=DEFAULT_SRID,with_z=false)
127
+ e = Envelope.new(srid,with_z)
128
+ e.lower_corner, e.upper_corner = points.collect{|point_coords| Point.from_coordinates(point_coords,srid,with_z)}
129
+ e
130
+ end
131
+
108
132
  end
109
133
  end
110
134
  end
@@ -33,7 +33,7 @@ module GeoRuby#:nodoc:
33
33
 
34
34
  #Returns an Envelope object for the geometry
35
35
  def envelope
36
- Envelope.new(bounding_box,srid,with_z)
36
+ Envelope.from_points(bounding_box,srid,with_z)
37
37
  end
38
38
 
39
39
  #Outputs the geometry as an EWKB string.
@@ -151,6 +151,21 @@ module GeoRuby#:nodoc:
151
151
  ewkt_parser.parse(ewkt)
152
152
  factory.geometry
153
153
  end
154
+
155
+ #sends back a geometry based on the GeoRSS string passed as argument
156
+ def self.from_georss(georss)
157
+ georss_parser= GeorssParser::new
158
+ georss_parser.parse(georss)
159
+ georss_parser.geometry
160
+ end
161
+
162
+ #sends back an array: The first element is the goemetry based on the GeoRSS string passed as argument. The second one is the GeoRSSTags (found only with the Simple format)
163
+ def self.from_georss_with_tags(georss)
164
+ georss_parser= GeorssParser::new
165
+ georss_parser.parse(georss,true)
166
+ [georss_parser.geometry, georss_parser.georss_tags]
167
+ end
168
+
154
169
  end
155
170
  end
156
171
  end
@@ -26,19 +26,35 @@ module GeoRuby
26
26
  def add_point_x_y(x,y)
27
27
  @geometry_stack.last.set_x_y(x,y)
28
28
  end
29
+ #add 2D points to the current geometry
30
+ def add_points_x_y(xy)
31
+ xy.each_slice(2) {|slice| add_point_x_y(*slice)}
32
+ end
29
33
  #add a 3D point to the current geometry
30
34
  def add_point_x_y_z(x,y,z)
31
35
  @geometry_stack.last.set_x_y_z(x,y,z)
32
36
  end
37
+ #add 3D points to the current geometry
38
+ def add_points_x_y_z(xyz)
39
+ xyz.each_slice(3) {|slice| add_point_x_y_z(*slice)}
40
+ end
33
41
  #add a 2D point with M to the current geometry
34
42
  def add_point_x_y_m(x,y,m)
35
43
  @geometry_stack.last.set_x_y(x,y)
36
44
  @geometry_stack.last.m=m
37
45
  end
46
+ #add 2D points with M to the current geometry
47
+ def add_points_x_y_m(xym)
48
+ xym.each_slice(3) {|slice| add_point_x_y_m(*slice)}
49
+ end
38
50
  #add a 3D point with M to the current geometry
39
51
  def add_point_x_y_z_m(x,y,z,m)
40
52
  @geometry_stack.last.set_x_y_z(x,y,z)
41
53
  @geometry_stack.last.m=m
54
+ end
55
+ #add 3D points with M to the current geometry
56
+ def add_points_x_y_z_m(xyzm)
57
+ xyzm.each_slice(4) {|slice| add_point_x_y_z_m(*slice)}
42
58
  end
43
59
  #begin a geometry of type +geometry_type+
44
60
  def begin_geometry(geometry_type,srid=DEFAULT_SRID)
@@ -0,0 +1,135 @@
1
+ require 'geo_ruby/simple_features/point'
2
+ require 'geo_ruby/simple_features/line_string'
3
+ require 'geo_ruby/simple_features/linear_ring'
4
+ require 'geo_ruby/simple_features/polygon'
5
+ require 'geo_ruby/simple_features/multi_point'
6
+ require 'geo_ruby/simple_features/multi_line_string'
7
+ require 'geo_ruby/simple_features/multi_polygon'
8
+ require 'geo_ruby/simple_features/geometry_collection'
9
+ require 'geo_ruby/simple_features/envelope'
10
+
11
+ module GeoRuby
12
+ module SimpleFeatures
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 =~ /<[^:>]*:LowerCorner\s*>([^<]*)</
81
+ lc = $1.split(" ").collect { |x| x.to_f}.reverse
82
+ if gml =~ /<[^:>]*: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.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.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.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.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
data/rakefile.rb CHANGED
@@ -24,7 +24,7 @@ spec = Gem::Specification::new do |s|
24
24
  s.platform = Gem::Platform::RUBY
25
25
 
26
26
  s.name = 'GeoRuby'
27
- s.version = "1.1.0"
27
+ s.version = "1.1.1"
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)
@@ -7,7 +7,7 @@ include GeoRuby::SimpleFeatures
7
7
 
8
8
  class TestGeorssKml < Test::Unit::TestCase
9
9
 
10
- def test_geometry_creation
10
+ def test_point_creation
11
11
  point = Point.from_x_y(3,4)
12
12
 
13
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",""))
@@ -65,4 +65,93 @@ class TestGeorssKml < Test::Unit::TestCase
65
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
66
  end
67
67
 
68
+ def test_point_georss_read
69
+ #W3CGeo
70
+ str = " <geo:lat >12.3</geo:lat >\n\t <geo:long> 4.56</geo:long> "
71
+ geom = Geometry.from_georss(str)
72
+ assert_equal(geom.class, Point)
73
+ assert_equal(12.3, geom.lat)
74
+ assert_equal(4.56, geom.lon)
75
+
76
+ str = " <geo:Point> \n \t <geo:long> 4.56</geo:long> \n\t <geo:lat >12.3</geo:lat > </geo:Point> "
77
+ geom = Geometry.from_georss(str)
78
+ assert_equal(geom.class, Point)
79
+ assert_equal(12.3, geom.lat)
80
+ assert_equal(4.56, geom.lon)
81
+
82
+ #gml
83
+ str = " <georss:where> \t\r <gml:Point > \t <gml:pos> 4 \t 3 </gml:pos> </gml:Point> </georss:where>"
84
+ geom = Geometry.from_georss(str)
85
+ assert_equal(geom.class, Point)
86
+ assert_equal(4, geom.lat)
87
+ assert_equal(3, geom.lon)
88
+
89
+
90
+ #simple
91
+ str = "<georss:point > 4 \r\t 3 \t</georss:point >"
92
+ geom = Geometry.from_georss(str)
93
+ assert_equal(geom.class, Point)
94
+ assert_equal(4, geom.lat)
95
+ assert_equal(3, geom.lon)
96
+
97
+ #simple with tags
98
+ str = "<georss:point featuretypetag=\"hoyoyo\" elev=\"45.7\" \n floor=\"2\" relationshiptag=\"puyopuyo\" radius=\"42\" > 4 \n 3 \t</georss:point >"
99
+ geom,tags = Geometry.from_georss_with_tags(str)
100
+ assert_equal(geom.class, Point)
101
+ assert_equal(4, geom.lat)
102
+ assert_equal(3, geom.lon)
103
+ assert_equal("hoyoyo",tags.featuretypetag)
104
+ assert_equal(45.7,tags.elev)
105
+ assert_equal("puyopuyo",tags.relationshiptag)
106
+ assert_equal(2,tags.floor)
107
+ assert_equal(42,tags.radius)
108
+ end
109
+
110
+ def test_line_string_georss_read
111
+ ls = LineString.from_points([Point.from_lon_lat(12.4,-45.3),Point.from_lon_lat(45.4,41.6)])
112
+
113
+ str = "<georss:line > -45.3 12.4 \n \r41.6\t 45.4</georss:line>"
114
+ geom = Geometry.from_georss(str)
115
+ assert_equal(geom.class, LineString)
116
+ assert_equal(ls ,geom)
117
+
118
+ str = "<georss:where><gml:LineString><gml:posList>-45.3 12.4 41.6 45.4</gml:posList></gml:LineString></georss:where>"
119
+ geom = Geometry.from_georss(str)
120
+ assert_equal(geom.class, LineString)
121
+ assert_equal(ls ,geom)
122
+
123
+ end
124
+
125
+ def test_polygon_georss_read
126
+ linear_ring = LinearRing.from_coordinates([[12.4,-45.3],[45.4,41.6],[4.456,1.0698],[12.4,-45.3]])
127
+ polygon = Polygon.from_linear_rings([linear_ring])
128
+
129
+ str = "<hoyoyo:polygon featuretypetag=\"42\" > -45.3 12.4 41.6 \n\r 45.4 1.0698 \r 4.456 -45.3 12.4 </hoyoyo:polygon>"
130
+ geom = Geometry.from_georss(str)
131
+ assert_equal(geom.class, Polygon)
132
+ assert_equal(polygon, geom)
133
+
134
+ str = "<georss:where>\r\t \n <gml:Polygon><gml:exterior> <gml:LinearRing><gml:posList> -45.3 \n\r 12.4 41.6 \n\t 45.4 1.0698 4.456 -45.3 12.4</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></georss:where>"
135
+ geom = Geometry.from_georss(str)
136
+ assert_equal(geom.class, Polygon)
137
+ assert_equal(polygon, geom)
138
+ end
139
+
140
+ def test_envelope_georss_read
141
+
142
+ e = Envelope.from_coordinates([[4.456,-45.3],[45.4,41.6]])
143
+
144
+ str = "<georss:box >-45.3 4.456 \n41.6 45.4</georss:box>"
145
+ geom = Geometry.from_georss(str)
146
+ assert_equal(geom.class, Envelope)
147
+ assert_equal(e, geom)
148
+
149
+ str = "<georss:where><gml:Envelope><gml:LowerCorner>-45.3 \n 4.456</gml:LowerCorner><gml:UpperCorner>41.6 \t\n 45.4</gml:UpperCorner></gml:Envelope></georss:where>"
150
+ geom = Geometry.from_georss(str)
151
+ assert_equal(geom.class, Envelope)
152
+ assert_equal(e, geom)
153
+
154
+ end
155
+
156
+
68
157
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: GeoRuby
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.1.0
7
- date: 2006-12-31 00:00:00 +01:00
6
+ version: 1.1.1
7
+ date: 2007-01-02 00:00:00 +01:00
8
8
  summary: Ruby data holder for OGC Simple Features
9
9
  require_paths:
10
10
  - lib
@@ -36,6 +36,7 @@ files:
36
36
  - lib/geo_ruby/simple_features/geometry.rb
37
37
  - lib/geo_ruby/simple_features/geometry_collection.rb
38
38
  - lib/geo_ruby/simple_features/geometry_factory.rb
39
+ - lib/geo_ruby/simple_features/georss_parser.rb
39
40
  - lib/geo_ruby/simple_features/linear_ring.rb
40
41
  - lib/geo_ruby/simple_features/line_string.rb
41
42
  - lib/geo_ruby/simple_features/multi_line_string.rb