georuby 1.9.7 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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