nofxx-georuby 1.3.9 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -1,8 +1,10 @@
1
- =GeoRuby
1
+ = GeoRuby
2
2
 
3
3
  This is a fork of GeoRuby. 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). It also supports various output and input formats (GeoRSS, KML, Shapefile).
4
4
 
5
- ===Available data types
5
+
6
+ === Available data types
7
+
6
8
  The following geometric data types are provided :
7
9
  - Point
8
10
  - Line string
@@ -17,17 +19,24 @@ They can be in 2D, 3DZ, 3DM, and 4D.
17
19
 
18
20
  On top of this an Envelope class is available, to contain the bounding box of a geometry.
19
21
 
20
- ===Input and output
22
+
23
+ === Input and output
24
+
21
25
  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.
22
26
 
23
27
  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). These formats can also be input and a GeoRuby geometry will be created. Note that it will not read a valid RSS file, only a geometry string.
24
28
 
25
29
  On top of that, there is now support for KML output and input. 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>clampToGround</tt>, the altitude data will not be output even if present. Envelopes output a LatLonAltBox instead of a geometry. For the output, the following geometric types are supported : Point, LineString, Polygon.
26
30
 
27
- ===SHP reading et writing
31
+
32
+ === SHP reading et writing
33
+
28
34
  Georuby has support for reading ESRI shapefiles (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf). A tool called <tt>shp2sql.rb</tt> is also provided : it shows how to use the SHP reading functionality together with the spatial adapter plugin for Rails to import spatial features into MySQL and PostGIS.
29
35
 
30
36
  Here is an example of Shapefile reading, that goes through all the geometries in a file and disaply the values of the attributes :
37
+
38
+ require 'geo_ruby/shp'
39
+
31
40
  ShpFile.open(shpfile) do |shp|
32
41
  shp.each do |shape|
33
42
  geom = shape.geometry #a GeoRuby SimpleFeature
@@ -41,10 +50,13 @@ Here is an example of Shapefile reading, that goes through all the geometries in
41
50
  Support for ESRI shapefile creation and modification has been added as well. New shapefiles can be created given a geometry type and specifications for the DBF fields. Data can be added and removed from an existing shapefile. An update operation is also provided for convenience : it just performs a 'delete' and an 'add', which means the index of the modified record will change. Note that once a shapefile has been created, GeoRuby does not allow the modification of the schema (it will probably be done in a subsequent version).
42
51
 
43
52
  Here is an example of how to create a new Shapefile with 2 fields :
53
+
44
54
  shpfile = ShpFile.create('hello.shp',ShpType::POINT,[Dbf::Field.new("Hoyoyo","C",10),Dbf::Field.new("Boyoul","N",10,0)])
55
+
45
56
  The file is then open for reading and writing.
46
57
 
47
58
  Here is an example of how to write to a shapefile (created or not with GeoRuby) :
59
+
48
60
  shpfile = ShpFile.open('places.shp')
49
61
  shpfile.transaction do |tr|
50
62
  tr.add(ShpRecord.new(Point.from_x_y(123.4,123.4),'Hoyoyo' => "AEZ",'Bouyoul' => 45))
@@ -57,27 +69,50 @@ Note the transaction is just there so the operations on the files can be buffere
57
69
 
58
70
  Also currently, error reporting is minimal and it has not been tested that thoroughly so caveat emptor and backup before performing any destructive operation.
59
71
 
60
- ===Installation
72
+
73
+ === GPX Reading
74
+
75
+ You can read and convert GPX Files to LineString/Polygon:
76
+
77
+ gpxfile = GpxFile.open(tour.gpx')
78
+ gpxfile.as_line_string
79
+ => GeoRuby::SimpleFeatures::LineString..
80
+
81
+
82
+ === Installation
83
+
61
84
  To install the latest version, just type :
62
- gem install GeoRuby
63
85
 
64
- ===Changes since the last version
86
+ gem install nofxx-georuby
87
+
88
+
89
+ === Changes since the last version
90
+
65
91
  - Writing of ESRI shapefiles
66
92
  - Reading of ESRI shapefiles
67
93
  - Addition of a small tool to import spatial features in MySQL and PostGIS from a SHP file
68
94
 
69
- ===Coming in the next versions
95
+
96
+ === Coming in the next versions
97
+
70
98
  - Schema modification of existing shapefiles
71
99
  - More error reporting when writing shapefiles
72
100
  - More tests on writing shapefiles ; tests on real-world shapefiles
73
101
  - Better shp2sql import tool
74
102
  - Documentation
75
103
 
76
- ===Acknowledgement
77
- The SHP reading part uses a modified version of the DBF library (http://rubyforge.org/projects/dbf/) by Keith Morrison (http://infused.org). Thanks also to Pramukta Kumar and Pete Schwamb for their contributions.
78
104
 
79
- ===License
105
+ === Acknowledgement
106
+
107
+ The SHP reading part uses the DBF library (http://rubyforge.org/projects/dbf/) by Keith Morrison (http://infused.org).
108
+ Thanks also to Pramukta Kumar and Pete Schwamb for their contributions.
109
+
110
+
111
+ === License
112
+
80
113
  GeoRuby is released under the MIT license.
81
114
 
82
- ===Support
83
- Any questions, enhancement proposals, bug notifications or corrections can be sent to mailto:guilhem.vellut@gmail.com.
115
+ === Support
116
+
117
+ Any questions, enhancement proposals, bug notifications or corrections
118
+ can be sent to mailto:guilhem.vellut@gmail.com.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.6.0
data/georuby.gemspec CHANGED
@@ -1,12 +1,15 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{georuby}
5
- s.version = "1.3.9"
8
+ s.version = "1.6.0"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["Guilhem Vellut", "Marcos Augusto"]
9
- s.date = %q{2009-05-07}
12
+ s.date = %q{2009-08-16}
10
13
  s.description = %q{GeoRuby provides geometric data types from the OGC 'Simple Features' specification.}
11
14
  s.email = %q{x@nofxx.com}
12
15
  s.extra_rdoc_files = [
@@ -19,9 +22,12 @@ Gem::Specification.new do |s|
19
22
  "LICENSE",
20
23
  "README.txt",
21
24
  "Rakefile",
22
- "VERSION.yml",
25
+ "VERSION",
23
26
  "georuby.gemspec",
24
27
  "lib/geo_ruby.rb",
28
+ "lib/geo_ruby/gpx.rb",
29
+ "lib/geo_ruby/gpx4r/gpx.rb",
30
+ "lib/geo_ruby/shp.rb",
25
31
  "lib/geo_ruby/shp4r/dbf.rb",
26
32
  "lib/geo_ruby/shp4r/shp.rb",
27
33
  "lib/geo_ruby/simple_features/envelope.rb",
@@ -43,6 +49,11 @@ Gem::Specification.new do |s|
43
49
  "script/destroy",
44
50
  "script/generate",
45
51
  "script/txt2html",
52
+ "spec/data/gpx/long.gpx",
53
+ "spec/data/gpx/long.kml",
54
+ "spec/data/gpx/long.nmea",
55
+ "spec/data/gpx/short.gpx",
56
+ "spec/data/gpx/short.kml",
46
57
  "spec/data/multipoint.dbf",
47
58
  "spec/data/multipoint.shp",
48
59
  "spec/data/multipoint.shx",
@@ -55,6 +66,7 @@ Gem::Specification.new do |s|
55
66
  "spec/data/polyline.dbf",
56
67
  "spec/data/polyline.shp",
57
68
  "spec/data/polyline.shx",
69
+ "spec/geo_ruby/gpx4r/gpx_spec.rb",
58
70
  "spec/geo_ruby/shp4r/shp_spec.rb",
59
71
  "spec/geo_ruby/simple_features/envelope_spec.rb",
60
72
  "spec/geo_ruby/simple_features/ewkb_parser_spec.rb",
@@ -74,30 +86,30 @@ Gem::Specification.new do |s|
74
86
  "spec/spec.opts",
75
87
  "spec/spec_helper.rb"
76
88
  ]
77
- s.has_rdoc = true
78
89
  s.homepage = %q{http://github.com/nofxx/georuby}
79
90
  s.rdoc_options = ["--charset=UTF-8"]
80
91
  s.require_paths = ["lib"]
81
- s.rubygems_version = %q{1.3.2}
92
+ s.rubygems_version = %q{1.3.5}
82
93
  s.summary = %q{Ruby data holder for OGC Simple Features}
83
94
  s.test_files = [
84
- "spec/geo_ruby/shp4r/shp_spec.rb",
85
- "spec/geo_ruby/simple_features/polygon_spec.rb",
86
- "spec/geo_ruby/simple_features/linear_ring_spec.rb",
95
+ "spec/geo_ruby_spec.rb",
96
+ "spec/spec_helper.rb",
97
+ "spec/geo_ruby/gpx4r/gpx_spec.rb",
98
+ "spec/geo_ruby/shp4r/shp_spec.rb",
99
+ "spec/geo_ruby/simple_features/point_spec.rb",
87
100
  "spec/geo_ruby/simple_features/geometry_factory_spec.rb",
88
- "spec/geo_ruby/simple_features/geometry_spec.rb",
89
- "spec/geo_ruby/simple_features/georss_parser_spec.rb",
90
- "spec/geo_ruby/simple_features/multi_point_spec.rb",
91
- "spec/geo_ruby/simple_features/ewkt_parser_spec.rb",
101
+ "spec/geo_ruby/simple_features/envelope_spec.rb",
102
+ "spec/geo_ruby/simple_features/polygon_spec.rb",
92
103
  "spec/geo_ruby/simple_features/line_string_spec.rb",
93
104
  "spec/geo_ruby/simple_features/multi_line_string_spec.rb",
94
- "spec/geo_ruby/simple_features/geometry_collection_spec.rb",
105
+ "spec/geo_ruby/simple_features/ewkt_parser_spec.rb",
95
106
  "spec/geo_ruby/simple_features/ewkb_parser_spec.rb",
107
+ "spec/geo_ruby/simple_features/linear_ring_spec.rb",
108
+ "spec/geo_ruby/simple_features/geometry_collection_spec.rb",
96
109
  "spec/geo_ruby/simple_features/multi_polygon_spec.rb",
97
- "spec/geo_ruby/simple_features/point_spec.rb",
98
- "spec/geo_ruby/simple_features/envelope_spec.rb",
99
- "spec/geo_ruby_spec.rb",
100
- "spec/spec_helper.rb"
110
+ "spec/geo_ruby/simple_features/multi_point_spec.rb",
111
+ "spec/geo_ruby/simple_features/georss_parser_spec.rb",
112
+ "spec/geo_ruby/simple_features/geometry_spec.rb"
101
113
  ]
102
114
 
103
115
  if s.respond_to? :specification_version then
data/lib/geo_ruby.rb CHANGED
@@ -16,4 +16,7 @@ require 'geo_ruby/simple_features/geometry_collection'
16
16
  require 'geo_ruby/simple_features/envelope'
17
17
  require 'geo_ruby/simple_features/geometry_factory'
18
18
  require 'geo_ruby/simple_features/georss_parser'
19
- require 'geo_ruby/shp4r/shp'
19
+
20
+ # Include if you need
21
+ # require 'geo_ruby/shp4r/shp'
22
+ # require 'geo_ruby/gpx4r/gpx'
@@ -0,0 +1 @@
1
+ require 'geo_ruby/gpx4r/gpx'
@@ -0,0 +1,109 @@
1
+ require "rubygems"
2
+ require "nokogiri"
3
+
4
+ module GeoRuby
5
+ module Gpx4r
6
+
7
+ #An interface to GPX files
8
+ class GpxFile
9
+ attr_reader :record_count, :file_root #:xmin, :ymin, :xmax, :ymax, :zmin, :zmax, :mmin, :mmax, :file_length
10
+
11
+ include Enumerable
12
+
13
+ # Opens a GPX file. Both "abc.shp" and "abc" are accepted.
14
+ def initialize(file, with_z = true, with_m = true)
15
+ @file_root = file.gsub(/\.gpx$/i,"")
16
+ raise MalformedGpxException.new("Missing GPX File") unless
17
+ File.exists? @file_root + ".gpx"
18
+ @points, @envelope = [], nil
19
+ @gpx = File.open(@file_root + ".gpx", "rb")
20
+ parse_file
21
+ end
22
+
23
+ #force the reopening of the files compsing the shp. Close before calling this.
24
+ def reload!
25
+ initialize(@file_root)
26
+ end
27
+
28
+ #opens a GPX "file". If a block is given, the GpxFile object is yielded to it and is closed upon return. Else a call to <tt>open</tt> is equivalent to <tt>GpxFile.new(...)</tt>.
29
+ def self.open(file)
30
+ gpxfile = GpxFile.new(file)
31
+ if block_given?
32
+ yield gpxfile
33
+ gpxfile.close
34
+ else
35
+ gpxfile
36
+ end
37
+ end
38
+
39
+ #Closes a gpxfile
40
+ def close
41
+ @gpx.close
42
+ end
43
+
44
+ #Tests if the file has no record
45
+ def empty?
46
+ record_count == 0
47
+ end
48
+
49
+ #Goes through each record
50
+ def each
51
+ (0...record_count).each do |i|
52
+ yield get_record(i)
53
+ end
54
+ end
55
+ alias :each_record :each
56
+
57
+ #Returns record +i+
58
+ def [](i)
59
+ get_record(i)
60
+ end
61
+
62
+ #Returns all the records
63
+ def records
64
+ @points
65
+ end
66
+
67
+ # Return the GPX file as LineString
68
+ def as_line_string
69
+ LineString.from_points(@points)
70
+ end
71
+ alias :as_polyline :as_line_string
72
+
73
+ # Return the GPX file as a Polygon
74
+ # If the GPX isn't closed, a line from the first
75
+ # to the last point will be created to close it.
76
+ def as_polygon
77
+ Polygon.from_points([@points << @points[-1]])
78
+ end
79
+
80
+ # Return GPX Envelope
81
+ def envelope
82
+ @envelope ||= as_polygon.envelope
83
+ end
84
+
85
+ private
86
+
87
+ def get_record(i)
88
+ @points[i]
89
+ end
90
+
91
+ def parse_file
92
+ Nokogiri.HTML(@gpx.read).search("//trkpt").each do |tp|
93
+ @points << Point.from_x_y_z_m(tp["lon"].to_f, tp["lat"].to_f, tp.at("ele").inner_text.to_i, tp.at("time").inner_text)
94
+ end
95
+ close
96
+ @record_count = @points.length
97
+ rescue => e
98
+ raise MalformedGpxException.new("Bad GPX. Error: #{e}")
99
+ # trackpoint.at("gpxdata:hr").nil? # heartrate
100
+ end
101
+
102
+ end
103
+
104
+ class MalformedGpxException < StandardError
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1 @@
1
+ require 'geo_ruby/shp4r/shp'
@@ -1,180 +1,37 @@
1
- # Copyright 2006 Keith Morrison (http://infused.org)
2
- # Modified version of his DBF library (http://rubyforge.org/projects/dbf/)
1
+ # Uses the dbf lib, Copyright 2006 Keith Morrison (http://infused.org)
2
+ # Modified to work as external gem now
3
+ require 'rubygems'
4
+ require 'dbf'
3
5
 
4
6
  module GeoRuby
5
7
  module Shp4r
6
- module Dbf
7
-
8
- DBF_HEADER_SIZE = 32
9
- DATE_REGEXP = /([\d]{4})([\d]{2})([\d]{2})/
10
- VERSION_DESCRIPTIONS = {
11
- "02" => "FoxBase",
12
- "03" => "dBase III without memo file",
13
- "04" => "dBase IV without memo file",
14
- "05" => "dBase V without memo file",
15
- "30" => "Visual FoxPro",
16
- "31" => "Visual FoxPro with AutoIncrement field",
17
- "7b" => "dBase IV with memo file",
18
- "83" => "dBase III with memo file",
19
- "8b" => "dBase IV with memo file",
20
- "8e" => "dBase IV with SQL table",
21
- "f5" => "FoxPro with memo file",
22
- "fb" => "FoxPro without memo file"
23
- }
24
-
25
- class DBFError < StandardError; end
26
- class UnpackError < DBFError; end
27
-
28
- class Reader
29
- attr_reader :field_count
30
- attr_reader :fields
31
- attr_reader :record_count
32
- attr_reader :version
33
- attr_reader :last_updated
34
- attr_reader :header_length
35
- attr_reader :record_length
36
-
37
- def initialize(file)
38
- @data_file = File.open(file, 'rb')
39
- reload!
40
- end
41
-
42
- def self.open(file)
43
- reader = Reader.new(file)
44
- if block_given?
45
- yield reader
46
- reader.close
47
- else
48
- reader
49
- end
50
- end
51
-
52
- def close
53
- @data_file.close
54
- end
55
-
56
- def reload!
57
- get_header_info
58
- get_field_descriptors
59
- end
60
-
61
- def field(field_name)
62
- @fields.detect {|f| f.name == field_name.to_s}
63
- end
64
-
65
- # An array of all the records contained in the database file
66
- def records
67
- seek_to_record(0)
68
- @records ||= Array.new(@record_count) do |i|
69
- if active_record?
70
- build_record
71
- else
72
- seek_to_record(i + 1)
73
- nil
74
- end
75
- end
76
- end
77
- alias_method :rows, :records
78
-
79
- # Jump to record
80
- def record(index)
81
- seek_to_record(index)
82
- active_record? ? build_record : nil
83
- end
84
-
85
- alias_method :row, :record
86
-
87
- def version_description
88
- VERSION_DESCRIPTIONS[version]
89
- end
90
-
91
- private
92
-
93
- def active_record?
94
- @data_file.read(1).unpack('H2').to_s == '20' rescue false
95
- end
8
+ Dbf = DBF
96
9
 
97
- def build_record
98
- record = DbfRecord.new
99
- @fields.each do |field|
100
- case field.type
101
- when 'N'
102
- record[field.name] = unpack_integer(field) rescue nil
103
- when 'F'
104
- record[field.name] = unpack_float(field) rescue nil
105
- when 'D'
106
- raw = unpack_string(field).to_s.strip
107
- unless raw.empty?
108
- begin
109
- record[field.name] = Time.gm(*raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i})
110
- rescue
111
- record[field.name] = Date.new(*raw.match(DATE_REGEXP).to_a.slice(1,3).map {|n| n.to_i}) rescue nil
112
- end
113
- end
114
- when 'L'
115
- record[field.name] = unpack_string(field) =~ /^(y|t)$/i ? true : false rescue false
116
- when 'C'
117
- record[field.name] = unpack_string(field).strip
118
- else
119
- record[field.name] = unpack_string(field)
120
- end
121
- end
122
- record
123
- end
124
-
125
- def get_header_info
126
- @data_file.rewind
127
- @version, @record_count, @header_length, @record_length = @data_file.read(DBF_HEADER_SIZE).unpack('H2xxxVvv')
128
- @field_count = (@header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE
129
- end
130
-
131
- def get_field_descriptors
132
- @fields = Array.new(@field_count) {|i| Field.new(*@data_file.read(32).unpack('a10xax4CC'))}
133
- end
134
-
135
- def seek(offset)
136
- @data_file.seek(@header_length + offset)
137
- end
138
-
139
- def seek_to_record(index)
140
- seek(@record_length * index)
141
- end
142
-
143
- def unpack_field(field)
144
- @data_file.read(field.length).unpack("a#{field.length}")
145
- end
146
-
147
- def unpack_string(field)
148
- unpack_field(field).to_s
149
- end
150
-
151
- def unpack_integer(field)
152
- unpack_string(field).to_i
10
+ module Dbf
11
+ class Record
12
+ def [](v)
13
+ attributes[v.downcase]
153
14
  end
15
+ end
154
16
 
155
- def unpack_float(field)
156
- unpack_string(field).to_f
17
+ class Field < Column
18
+ def initialize(name, type, length, decimal = 0)
19
+ super(name, type, length, decimal)
157
20
  end
158
-
159
21
  end
160
22
 
161
- class FieldError < StandardError; end
162
-
163
- class Field
164
- attr_reader :name, :type, :length, :decimal
23
+ class Reader < Table
24
+ alias_method :fields, :columns
25
+ def header_length
26
+ @columns_count
27
+ end
165
28
 
166
- def initialize(name, type, length, decimal = 0)
167
- raise FieldError, "field length must be greater than 0" unless length > 0
168
- if type == 'N' and decimal != 0
169
- type = 'F'
170
- end
171
- @name, @type, @length, @decimal = name.strip, type,length, decimal
29
+ def self.open(f)
30
+ new(f)
172
31
  end
173
- end
174
32
 
175
- class DbfRecord < Hash
33
+ def close(); nil; end
176
34
  end
177
-
178
35
  end
179
36
  end
180
37
  end