georuby 1.9.7 → 1.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,9 +1,7 @@
1
1
  = GeoRuby
2
2
 
3
3
 
4
- This is a fork of GeoRuby with some updates and extra funcionality.
5
-
6
- It is intended as a holder for geometric data. The data model roughly
4
+ This is intended as a holder for geometric data. The data model roughly
7
5
  follows the OGC "Simple Features for SQL" specification, so it should
8
6
  play nice with data returned from PostGIS or any Spatial Extensions (MongoDB, MySQL...).
9
7
  Although without any kind of advanced functionalities (such as geometric operators or reprojections).
@@ -12,7 +10,7 @@ It also supports various output and input formats (GeoRSS, KML, Shapefile).
12
10
  OGC:"http://www.opengis.org/docs/99-049.pdf"
13
11
 
14
12
  GeoRuby is written in pure Ruby.
15
- If you are looking for Proj/Geos/ext rubygem checkout:
13
+ If you are looking for Proj/Geos/ext C rubygem checkout:
16
14
  rgeo:"https://github.com/dazuma/rgeo"
17
15
 
18
16
 
@@ -36,7 +34,11 @@ On top of this an Envelope class is available, to contain the bounding box of a
36
34
 
37
35
  To install the latest version, just type:
38
36
 
39
- gem install nofxx-georuby
37
+ gem install georuby
38
+
39
+ Or include on your projects`s Gemfile:
40
+
41
+ gem 'georuby'
40
42
 
41
43
 
42
44
  == Use
data/lib/geo_ruby.rb CHANGED
@@ -17,7 +17,8 @@ require 'geo_ruby/simple_features/envelope'
17
17
  require 'geo_ruby/simple_features/geometry_factory'
18
18
 
19
19
  # Require if you need
20
- # require 'geo_ruby/shp4r/shp'
21
- # require 'geo_ruby/gpx4r/gpx'
22
- # require 'geo_ruby/geojson'
23
- # require 'geo_ruby/georss'
20
+ require 'geo_ruby/shp4r/shp'
21
+ require 'geo_ruby/gpx4r/gpx'
22
+ require 'geo_ruby/geojson'
23
+ require 'geo_ruby/georss'
24
+ require 'geo_ruby/kml'
@@ -0,0 +1,84 @@
1
+ require 'rexml/parsers/pullparser'
2
+ module GeoRuby
3
+ class KmlParser
4
+ ELEMENT_MAP = {
5
+ # "Point" => SimpleFeatures::Point, # we don't need to map points. they are done automatically by the coordinate parsing
6
+ "LineString" => SimpleFeatures::LineString,
7
+ "LinearRing" => SimpleFeatures::LinearRing,
8
+ "Polygon" => SimpleFeatures::Polygon,
9
+ "MultiGeometry" => SimpleFeatures::GeometryCollection
10
+ }
11
+ def initialize(factory)
12
+ @factory = factory
13
+ @buffer = ""
14
+ @with_z = false
15
+ end
16
+ # argument should be a valid kml geometry fragment ie. <Point> .... </Point>
17
+ # returns the GeoRuby geometry object back
18
+ def parse(kml)
19
+ @factory.reset
20
+ @with_z = false
21
+ @parser = REXML::Parsers::PullParser.new(kml)
22
+ while @parser.has_next?
23
+ e = @parser.pull
24
+ if e.start_element?
25
+ if(type = ELEMENT_MAP[e[0]])
26
+ @factory.begin_geometry(type)
27
+ else
28
+ @buffer = "" if(e[0] == "coordinates") # clear the buffer
29
+ accumulate_start(e)
30
+ end
31
+ elsif e.end_element?
32
+ if(ELEMENT_MAP[e[0]])
33
+ @factory.end_geometry(@with_z)
34
+ @buffer = "" # clear the buffer
35
+ else
36
+ accumulate_end(e)
37
+ if(e[0] == "coordinates")
38
+ parse_coordinates(@buffer)
39
+ @buffer = "" # clear the buffer
40
+ end
41
+ end
42
+ elsif e.text?
43
+ accumulate_text(e)
44
+ elsif e.cdata?
45
+ accumulate_cdata(e)
46
+ end
47
+ end
48
+ @factory.geometry.dup
49
+ end
50
+
51
+ private
52
+ def accumulate_text(e); @buffer << e[0]; end
53
+ def accumulate_cdata(e); @buffer << "<![CDATA[#{e[0]}]]>"; end
54
+ def accumulate_start(e)
55
+ @buffer << "<#{e[0]}"
56
+ if(e[1].class == Hash)
57
+ e[1].each_pair {|k,v| @buffer << " #{k}='#{v}'" }
58
+ end
59
+ @buffer << ">"
60
+ end
61
+ def accumulate_end(e); @buffer << "</#{e[0]}>"; end
62
+
63
+ def parse_coordinates(buffer)
64
+ if(buffer =~ /<coordinates>(.+)<\/coordinates>/)
65
+ $1.gsub(/\n/, " ").strip.split(/\s+/).each do |coord|
66
+ x,y,z = coord.split(',')
67
+ if(x.nil? || y.nil?)
68
+ raise StandardError, "coordinates must have at least x and y elements"
69
+ end
70
+ @factory.begin_geometry(SimpleFeatures::Point)
71
+ if(z.nil?)
72
+ @factory.add_point_x_y(x,y)
73
+ else
74
+ @factory.add_point_x_y_z(x,y,z)
75
+ @with_z = true unless @with_z # is the conditional even necessary
76
+ end
77
+ @factory.end_geometry(@with_z)
78
+ end
79
+ end
80
+ rescue
81
+ raise StandardError, "error parsing coordinates: check your kml for errors"
82
+ end
83
+ end
84
+ end
@@ -175,47 +175,12 @@ module GeoRuby#:nodoc:
175
175
  end
176
176
 
177
177
  #Sends back a geometry from a KML encoded geometry string.
178
- #Limitations : Only supports points, linestrings and polygons (no collection for now).
179
- #Addapted from Pramukta's code
180
178
  def self.from_kml(kml)
181
- return GeoRuby::SimpleFeatures::Geometry.from_ewkt(kml_to_wkt(kml))
182
- end
183
-
184
- require 'rexml/document'
185
- def self.kml_to_wkt(kml)
186
- doc = REXML::Document.new(kml)
187
- wkt = ""
188
- if ["Point", "LineString", "Polygon" ].include?(doc.root.name)
189
- case doc.root.name
190
- when "Point" then
191
- coords = doc.elements["/Point/coordinates"].text.gsub(/\n/," ")
192
- wkt = doc.root.name.upcase + "(" + split_coords(coords).join(' ') + ")"
193
- when "LineString" then
194
- coords = doc.elements["/LineString/coordinates"].text.gsub(/\n/," ")
195
- coords = split_coords(coords)
196
- wkt = doc.root.name.upcase + "(" + coords.join(",") + ")"
197
- when "Polygon" then
198
- # polygons have one outer ring and zero or more inner rings
199
- bounds = []
200
- bounds << doc.elements["/Polygon/outerBoundaryIs/LinearRing/coordinates"].text
201
- inner_coords_elements = doc.elements.each("/Polygon/innerBoundaryIs/LinearRing/coordinates") do |inner_coords|
202
- inner_coords = inner_coords.text
203
- bounds << inner_coords
204
- end
205
-
206
- wkt = doc.root.name.upcase + "(" + bounds.map do |bound|
207
- bound.gsub!(/\n/, " ")
208
- bound = split_coords(bound)
209
- if bound.first != bound.last
210
- bound.push bound.first
211
- end
212
- "(" + bound.join(",") + ")"
213
- end.join(",") + ")"
214
- end
215
- end
216
- return wkt
179
+ factory = GeometryFactory.new
180
+ parser = KmlParser.new(factory)
181
+ parser.parse(kml)
217
182
  end
218
-
183
+
219
184
  # Some GeoJSON files do not include srid info, so
220
185
  # we provide an optional parameter
221
186
  def self.from_geojson(geojson, srid=DEFAULT_SRID)
@@ -12,21 +12,26 @@ module GeoRuby
12
12
  super(srid,with_z,with_m)
13
13
  end
14
14
 
15
+ # fix kml export
16
+ alias_method :orig_kml_representation, :kml_representation
17
+ def kml_representation(options = {})
18
+ orig_kml_representation(options).gsub('LineString', 'LinearRing')
19
+ end
15
20
 
16
- # Does this linear string contain the given point? We use the
17
- # algorithm described here:
18
- #
19
- # http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
20
- def contains_point?(point)
21
- x, y = point.x, point.y
22
- tuples = @points.zip(@points[1..-1] + [@points[0]])
23
- crossings =
24
- tuples.select do |a, b|
25
- (b.y > y != a.y > y) && (x < (a.x - b.x) * (y - b.y) / (a.y - b.y) + b.x)
26
- end
27
-
28
- crossings.size % 2 == 1
29
- end
21
+ # Does this linear string contain the given point? We use the
22
+ # algorithm described here:
23
+ #
24
+ # http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
25
+ def contains_point?(point)
26
+ x, y = point.x, point.y
27
+ tuples = @points.zip(@points[1..-1] + [@points[0]])
28
+ crossings =
29
+ tuples.select do |a, b|
30
+ (b.y > y != a.y > y) && (x < (a.x - b.x) * (y - b.y) / (a.y - b.y) + b.x)
31
+ end
32
+
33
+ crossings.size % 2 == 1
34
+ end
30
35
  end
31
36
 
32
37
  end
@@ -1,3 +1,3 @@
1
1
  module GeoRuby
2
- VERSION = '1.9.7'
2
+ VERSION = '1.9.8'
3
3
  end
@@ -0,0 +1,79 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe KmlParser do
4
+ before(:all) do
5
+ POINT = "<Point><coordinates>-82.4898187291883,34.2473206042649</coordinates></Point>"
6
+ LINESTRING = "<LineString><coordinates>-122.365662,37.826988 -122.365202,37.826302 -122.364581,37.82655 -122.365038,37.827237</coordinates></LineString>"
7
+ LINEARRING = "<LinearRing><coordinates>-122.365662,37.826988 -122.365202,37.826302 -122.364581,37.82655 -122.365038,37.827237 -122.365662,37.826988</coordinates></LinearRing>"
8
+ POLYGON = "<Polygon><outerBoundaryIs><LinearRing><coordinates>-82.5961385808407,34.0134202383713 -82.6029437979289,34.0346366848087 -82.6603553035687,34.1083560439036 -82.7357807829899,34.1697961502507 -82.7425935601244,34.2055536194311 -82.3145921793097,34.4812209701586 -82.2758648198483,34.4347213073308 -82.2405017851073,34.4067761024174 -82.3327002190662,34.3417863447576 -82.2910826671599,34.2708004396966 -82.2497468801283,34.2261551348023 -82.2370438982521,34.1709424545969 -82.2569955519648,34.1119142196088 -82.3237086862075,34.0601294413679 -82.368425596693,34.0533120146082 -82.4455985300521,34.0562556252352 -82.4806178108032,34.0759686807282 -82.5334224196077,34.0620944842448 -82.5961385808407,34.0134202383713</coordinates></LinearRing></outerBoundaryIs></Polygon>"
9
+ COMPLEX_POLYGON = "<Polygon><outerBoundaryIs><LinearRing><coordinates>-122.366278,37.818844 -122.365248,37.819267 -122.365640,37.819861 -122.366669,37.819429 -122.366278,37.818844</coordinates></LinearRing></outerBoundaryIs><innerBoundaryIs><LinearRing><coordinates>-122.366212,37.818977 -122.365424,37.819294 -122.365704,37.819731 -122.366488,37.819402 -122.366212,37.818977</coordinates></LinearRing></innerBoundaryIs></Polygon>"
10
+ MULTIGEOMETRY = "<MultiGeometry><Polygon><outerBoundaryIs><LinearRing><coordinates>-82.5961385808407,34.0134202383713 -82.6029437979289,34.0346366848087 -82.6603553035687,34.1083560439036 -82.7357807829899,34.1697961502507 -82.7425935601244,34.2055536194311 -82.3145921793097,34.4812209701586 -82.2758648198483,34.4347213073308 -82.2405017851073,34.4067761024174 -82.3327002190662,34.3417863447576 -82.2910826671599,34.2708004396966 -82.2497468801283,34.2261551348023 -82.2370438982521,34.1709424545969 -82.2569955519648,34.1119142196088 -82.3237086862075,34.0601294413679 -82.368425596693,34.0533120146082 -82.4455985300521,34.0562556252352 -82.4806178108032,34.0759686807282 -82.5334224196077,34.0620944842448 -82.5961385808407,34.0134202383713</coordinates></LinearRing></outerBoundaryIs></Polygon><Point><coordinates>-82.4898187291883,34.2473206042649</coordinates></Point></MultiGeometry>"
11
+
12
+ POINT3D = "<Point><coordinates>-82.4898187291883,34.2473206042649,5</coordinates></Point>"
13
+ LINESTRING3D = "<LineString><coordinates>-122.365662,37.826988,1 -122.365202,37.826302,2 -122.364581,37.82655,3 -122.365038,37.827237,4</coordinates></LineString>"
14
+ end
15
+
16
+ before(:each) do
17
+ @factory = GeometryFactory.new
18
+ @kml_parser = KmlParser.new(@factory)
19
+ end
20
+
21
+ it "should parse a Point correctly" do
22
+ @kml_parser.parse(POINT)
23
+ g = @factory.geometry
24
+ g.should_not eql(nil)
25
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::Point)
26
+ g.as_kml.gsub(/\n/,'').should eql(POINT)
27
+ end
28
+
29
+ it "should parse a LineString correctly" do
30
+ @kml_parser.parse(LINESTRING)
31
+ g = @factory.geometry
32
+ g.should_not eql(nil)
33
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::LineString)
34
+ g.as_kml.gsub(/\n/,'').should eql(LINESTRING)
35
+
36
+ @kml_parser.parse(LINEARRING)
37
+ g = @factory.geometry
38
+ g.should_not eql(nil)
39
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::LinearRing)
40
+ g.as_kml.gsub(/\n/,'').should eql(LINEARRING)
41
+ end
42
+
43
+ it "should parse a Polygon correctly" do
44
+ @kml_parser.parse(POLYGON)
45
+ g = @factory.geometry
46
+ g.should_not eql(nil)
47
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::Polygon)
48
+ g.as_kml.gsub(/\n/,'').should eql(POLYGON)
49
+
50
+ @kml_parser.parse(COMPLEX_POLYGON)
51
+ g = @factory.geometry
52
+ g.should_not eql(nil)
53
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::Polygon)
54
+ g.as_kml.gsub(/\n/,'').should eql(COMPLEX_POLYGON)
55
+ end
56
+
57
+ it "should parse a MultiGeometry correctly" do
58
+ @kml_parser.parse(MULTIGEOMETRY)
59
+ g = @factory.geometry
60
+ g.should_not eql(nil)
61
+ g.geometries.length.should eql(2)
62
+ g.should be_an_instance_of(GeoRuby::SimpleFeatures::GeometryCollection)
63
+ g.as_kml.gsub(/\n/,'').should eql(MULTIGEOMETRY)
64
+ end
65
+
66
+ it "should parse 3D geometries correctly" do
67
+ # not testing generation because GeoRuby kml generation logic currently requires additional
68
+ # XML nodes to actually output 3D coordinate information. I might modify that behavior
69
+ g = @kml_parser.parse(POINT3D)
70
+ g.should_not eql(nil)
71
+ g.with_z.should eql(true)
72
+ # g.as_kml(:altitude_mode => "clampToGround").gsub(/\n/,'').should eql(POINT3D)
73
+
74
+ g = @kml_parser.parse(LINESTRING3D)
75
+ g.should_not eql(nil)
76
+ g.with_z.should eql(true)
77
+ # g.as_kml(:altitude_mode => "clampToGround").gsub(/\n/,'').should eql(LINESTRING3D)
78
+ end
79
+ end
data/spec/spec_helper.rb CHANGED
@@ -18,6 +18,7 @@ require 'geo_ruby/shp'
18
18
  require 'geo_ruby/gpx'
19
19
  require 'geo_ruby/geojson'
20
20
  require 'geo_ruby/georss'
21
+ require 'geo_ruby/kml'
21
22
 
22
23
  include GeoRuby
23
24
  include SimpleFeatures
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: georuby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.7
4
+ version: 1.9.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,11 +12,11 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-03-31 00:00:00.000000000 Z
15
+ date: 2012-09-09 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: dbf
19
- requirement: &15986320 !ruby/object:Gem::Requirement
19
+ requirement: !ruby/object:Gem::Requirement
20
20
  none: false
21
21
  requirements:
22
22
  - - ! '>='
@@ -24,10 +24,15 @@ dependencies:
24
24
  version: 1.2.9
25
25
  type: :development
26
26
  prerelease: false
27
- version_requirements: *15986320
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.9
28
33
  - !ruby/object:Gem::Dependency
29
34
  name: rspec
30
- requirement: &15998420 !ruby/object:Gem::Requirement
35
+ requirement: !ruby/object:Gem::Requirement
31
36
  none: false
32
37
  requirements:
33
38
  - - ! '>='
@@ -35,7 +40,12 @@ dependencies:
35
40
  version: 2.0.0
36
41
  type: :development
37
42
  prerelease: false
38
- version_requirements: *15998420
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: 2.0.0
39
49
  description: GeoRuby provides geometric data types from the OGC 'Simple Features'
40
50
  specification.
41
51
  email: x@nofxx.com
@@ -66,6 +76,7 @@ files:
66
76
  - lib/geo_ruby/simple_features/ewkb_parser.rb
67
77
  - lib/geo_ruby/shp4r/shp.rb
68
78
  - lib/geo_ruby/shp4r/dbf.rb
79
+ - lib/geo_ruby/kml.rb
69
80
  - lib/geo_ruby/georss.rb
70
81
  - spec/geo_ruby_spec.rb
71
82
  - spec/data/point.dbf
@@ -92,6 +103,7 @@ files:
92
103
  - spec/data/polygon.shx
93
104
  - spec/data/polygon.shp
94
105
  - spec/spec_helper.rb
106
+ - spec/geo_ruby/kml_spec.rb
95
107
  - spec/geo_ruby/gpx4r/gpx_spec.rb
96
108
  - spec/geo_ruby/geojson_spec.rb
97
109
  - spec/geo_ruby/simple_features/multi_line_string_spec.rb
@@ -126,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
138
  version: '0'
127
139
  segments:
128
140
  - 0
129
- hash: -4339575636019116239
141
+ hash: 3326906326237505079
130
142
  required_rubygems_version: !ruby/object:Gem::Requirement
131
143
  none: false
132
144
  requirements:
@@ -135,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
147
  version: '0'
136
148
  requirements: []
137
149
  rubyforge_project:
138
- rubygems_version: 1.8.11
150
+ rubygems_version: 1.8.23
139
151
  signing_key:
140
152
  specification_version: 3
141
153
  summary: Ruby data holder for OGC Simple Features