nofxx-georuby 1.3.7
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/History.txt +4 -0
- data/LICENSE +21 -0
- data/README.txt +59 -0
- data/Rakefile +49 -0
- data/VERSION.yml +4 -0
- data/lib/geo_ruby.rb +21 -0
- data/lib/geo_ruby/base/envelope.rb +167 -0
- data/lib/geo_ruby/base/ewkb_parser.rb +216 -0
- data/lib/geo_ruby/base/ewkt_parser.rb +336 -0
- data/lib/geo_ruby/base/geometry.rb +234 -0
- data/lib/geo_ruby/base/geometry_collection.rb +136 -0
- data/lib/geo_ruby/base/geometry_factory.rb +81 -0
- data/lib/geo_ruby/base/georss_parser.rb +135 -0
- data/lib/geo_ruby/base/helper.rb +18 -0
- data/lib/geo_ruby/base/line_string.rb +184 -0
- data/lib/geo_ruby/base/linear_ring.rb +12 -0
- data/lib/geo_ruby/base/multi_line_string.rb +39 -0
- data/lib/geo_ruby/base/multi_point.rb +41 -0
- data/lib/geo_ruby/base/multi_polygon.rb +37 -0
- data/lib/geo_ruby/base/point.rb +310 -0
- data/lib/geo_ruby/base/polygon.rb +150 -0
- data/lib/geo_ruby/shp4r/dbf.rb +180 -0
- data/lib/geo_ruby/shp4r/shp.rb +701 -0
- data/spec/data/multipoint.dbf +0 -0
- data/spec/data/multipoint.shp +0 -0
- data/spec/data/multipoint.shx +0 -0
- data/spec/data/point.dbf +0 -0
- data/spec/data/point.shp +0 -0
- data/spec/data/point.shx +0 -0
- data/spec/data/polygon.dbf +0 -0
- data/spec/data/polygon.shp +0 -0
- data/spec/data/polygon.shx +0 -0
- data/spec/data/polyline.dbf +0 -0
- data/spec/data/polyline.shp +0 -0
- data/spec/data/polyline.shx +0 -0
- data/spec/geo_ruby/base/envelope_spec.rb +45 -0
- data/spec/geo_ruby/base/ewkb_parser_spec.rb +158 -0
- data/spec/geo_ruby/base/ewkt_parser_spec.rb +179 -0
- data/spec/geo_ruby/base/geometry_collection_spec.rb +55 -0
- data/spec/geo_ruby/base/geometry_factory_spec.rb +11 -0
- data/spec/geo_ruby/base/geometry_spec.rb +32 -0
- data/spec/geo_ruby/base/georss_parser_spec.rb +218 -0
- data/spec/geo_ruby/base/line_string_spec.rb +208 -0
- data/spec/geo_ruby/base/linear_ring_spec.rb +14 -0
- data/spec/geo_ruby/base/multi_line_string_spec.rb +35 -0
- data/spec/geo_ruby/base/multi_point_spec.rb +29 -0
- data/spec/geo_ruby/base/multi_polygon_spec.rb +35 -0
- data/spec/geo_ruby/base/point_spec.rb +275 -0
- data/spec/geo_ruby/base/polygon_spec.rb +108 -0
- data/spec/geo_ruby/shp4r/shp_spec.rb +238 -0
- data/spec/geo_ruby_spec.rb +27 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +12 -0
- metadata +123 -0
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
GeoRuby License
|
2
|
+
|
3
|
+
Copyright (c) 2006 Guilhem Vellut <guilhem.vellut+georuby@gmail.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to
|
7
|
+
deal in the Software without restriction, including without limitation the
|
8
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to the
|
10
|
+
following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
16
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
18
|
+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
19
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
20
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
21
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.txt
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= geo_ruby
|
2
|
+
|
3
|
+
Experiment with GeoRuby (http://georuby.rubyforge.org) with the fast Geo (http://geo.rubyforge.org).
|
4
|
+
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
the objective is provide all the georuby functionalities, with time consuming calculus in C.
|
9
|
+
_this is not usable yet_
|
10
|
+
|
11
|
+
See:
|
12
|
+
GeoRuby (http://georuby.rubyforge.org)
|
13
|
+
Copyright (c) 2006 Guilhem Vellut <guilhem.vellut+georuby@gmail.com>
|
14
|
+
|
15
|
+
Geo (http://geo.rubyforge.org)
|
16
|
+
Copyright (C) 2007 Martin Kihlgren
|
17
|
+
|
18
|
+
|
19
|
+
== REQUIREMENTS:
|
20
|
+
|
21
|
+
glib:: http://www.gtk.org/
|
22
|
+
|
23
|
+
== FEATURES:
|
24
|
+
|
25
|
+
=Available data types
|
26
|
+
|
27
|
+
- Point
|
28
|
+
- Line string
|
29
|
+
- Linear ring
|
30
|
+
- Polygon
|
31
|
+
- Multi point
|
32
|
+
- Multi line string
|
33
|
+
- Multi polygon
|
34
|
+
- Geometry collection
|
35
|
+
|
36
|
+
They can be in 2D, 3DZ, 3DM, and 4D.
|
37
|
+
|
38
|
+
|
39
|
+
Geo::Point:: A 2D point providing some common geometry operations.
|
40
|
+
Geo::Line:: A 2D line consisting of 2 Geo::Points providing some common geometry operations.
|
41
|
+
Geo::Triangle:: A 2D triangle consisting of 3 Geo::Points providing some common geometry operations.
|
42
|
+
Geo::PointSet:: A Set-like container of Points.
|
43
|
+
Geo::LineSet:: A Set-like container of Lines that provides optimized versions of some common geometry operations on lines.
|
44
|
+
Geo::TriangleSet:: A Set-like container of Triangles that provides optimized versions of some common geometry operations on lines.
|
45
|
+
|
46
|
+
== Usage:
|
47
|
+
|
48
|
+
Just install the gem.
|
49
|
+
|
50
|
+
== Examples:
|
51
|
+
|
52
|
+
To find if a given line intersects a set of 100 000 other lines:
|
53
|
+
|
54
|
+
:include:examples/intersects.rb
|
55
|
+
|
56
|
+
== License:
|
57
|
+
|
58
|
+
GeoRuby is released under the MIT license.
|
59
|
+
geo is provided under the GPL-2.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "georuby"
|
8
|
+
gem.summary = "Ruby data holder for OGC Simple Features"
|
9
|
+
gem.description = "GeoRuby provides geometric data types from the OGC 'Simple Features' specification."
|
10
|
+
gem.email = "x@nofxx.com"
|
11
|
+
gem.homepage = "http://github.com/nofxx/georuby"
|
12
|
+
gem.authors = ["Guilhem Vellut", "Marcos Augusto"]
|
13
|
+
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'spec/rake/spectask'
|
21
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
22
|
+
spec.libs << 'lib' << 'spec'
|
23
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
24
|
+
end
|
25
|
+
|
26
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
27
|
+
spec.libs << 'lib' << 'spec'
|
28
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
29
|
+
spec.rcov = true
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
task :default => :spec
|
34
|
+
|
35
|
+
require 'rake/rdoctask'
|
36
|
+
Rake::RDocTask.new do |rdoc|
|
37
|
+
if File.exist?('VERSION.yml')
|
38
|
+
config = YAML.load(File.read('VERSION.yml'))
|
39
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
40
|
+
else
|
41
|
+
version = ""
|
42
|
+
end
|
43
|
+
|
44
|
+
rdoc.rdoc_dir = 'rdoc'
|
45
|
+
rdoc.title = "geo_ruby #{version}"
|
46
|
+
rdoc.rdoc_files.include('README*')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
49
|
+
|
data/VERSION.yml
ADDED
data/lib/geo_ruby.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'geo_ruby/base/helper'
|
5
|
+
require 'geo_ruby/base/ewkt_parser'
|
6
|
+
require 'geo_ruby/base/ewkb_parser'
|
7
|
+
require 'geo_ruby/base/geometry'
|
8
|
+
require 'geo_ruby/base/point'
|
9
|
+
require 'geo_ruby/base/line_string'
|
10
|
+
require 'geo_ruby/base/linear_ring'
|
11
|
+
require 'geo_ruby/base/polygon'
|
12
|
+
require 'geo_ruby/base/multi_point'
|
13
|
+
require 'geo_ruby/base/multi_line_string'
|
14
|
+
require 'geo_ruby/base/multi_polygon'
|
15
|
+
require 'geo_ruby/base/geometry_collection'
|
16
|
+
require 'geo_ruby/base/envelope'
|
17
|
+
require 'geo_ruby/base/geometry_factory'
|
18
|
+
require 'geo_ruby/base/georss_parser'
|
19
|
+
require 'geo_ruby/shp4r/shp'
|
20
|
+
|
21
|
+
GeoRuby::SimpleFeatures = GeoRuby::Base
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module GeoRuby
|
2
|
+
module Base
|
3
|
+
|
4
|
+
#Contains the bounding box of a geometry
|
5
|
+
class Envelope
|
6
|
+
attr_accessor :lower_corner, :upper_corner
|
7
|
+
attr_accessor :srid, :with_z, :zoom
|
8
|
+
|
9
|
+
#Creates a enw Envelope with +lower_corner+ as the first element of the corners array and +upper_corner+ as the second element
|
10
|
+
def initialize(srid = @@default_srid, with_z = false)
|
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.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
|
+
e.extend!(envelope)
|
30
|
+
e
|
31
|
+
end
|
32
|
+
# def bounding_box(markers)
|
33
|
+
# max_lat, max_lon, min_lat, min_lon = -Float::MAX, -Float::MAX, Float::MAX, Float::MAX
|
34
|
+
# markers.each do |marker|
|
35
|
+
# coord = marker.point
|
36
|
+
# max_lat = coord.lat if coord.lat > max_lat
|
37
|
+
# min_lat = coord.lat if coord.lat < min_lat
|
38
|
+
# max_lon = coord.lng if coord.lng > max_lon
|
39
|
+
# min_lon = coord.lng if coord.lng < min_lon
|
40
|
+
# end
|
41
|
+
# min_point = Point.from_x_y(min_lat,min_lon)
|
42
|
+
# max_point = Point.from_x_y(max_lat,max_lon)
|
43
|
+
|
44
|
+
# end
|
45
|
+
# centrelat = (max_lat + min_lat)/2
|
46
|
+
# centrelng = (max_lon + min_lon)/2
|
47
|
+
# # logger.info("distance[#{distance}],zoom[#{zoom}]")
|
48
|
+
# #return GLatLngBounds.new(GLatLng.new(min_point),GLatLng.new(max_point)), [centrelat,centrelng], zoom
|
49
|
+
# return [centrelat,centrelng], zoom
|
50
|
+
|
51
|
+
#Sends back the center of the envelope
|
52
|
+
def center
|
53
|
+
Point.from_x_y((lower_corner.x + upper_corner.x)/2,(lower_corner.y + upper_corner.y)/2)
|
54
|
+
end
|
55
|
+
|
56
|
+
#Zoom level
|
57
|
+
def zoom
|
58
|
+
distance = lower_corner.spherical_distance(upper_corner)/10000
|
59
|
+
@zoom = case distance
|
60
|
+
when 150..9000 then 5
|
61
|
+
when 80..149 then 6
|
62
|
+
when 50..79 then 7
|
63
|
+
when 20..49 then 8
|
64
|
+
when 10..19 then 9
|
65
|
+
when 5..9 then 10
|
66
|
+
else 13
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#Tests the equality of line strings
|
71
|
+
def ==(other_envelope)
|
72
|
+
if other_envelope.class != self.class
|
73
|
+
false
|
74
|
+
else
|
75
|
+
upper_corner == other_envelope.upper_corner and lower_corner == other_envelope.lower_corner
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#georss serialization: Dialect can be passed as option <tt>:dialect</tt> and set to <tt>:simple</tt> (default)
|
80
|
+
#<tt>:w3cgeo</tt> or <tt>:gml</tt>. Options <tt>:featuretypetag
|
81
|
+
def as_georss(options = {})
|
82
|
+
dialect= options[:dialect] || :simple
|
83
|
+
case(dialect)
|
84
|
+
when :simple
|
85
|
+
geom_attr = ""
|
86
|
+
geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
|
87
|
+
geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
|
88
|
+
geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
|
89
|
+
geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
|
90
|
+
geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
|
91
|
+
|
92
|
+
georss_simple_representation(options.merge(:geom_attr => geom_attr))
|
93
|
+
when :w3cgeo
|
94
|
+
georss_w3cgeo_representation(options)
|
95
|
+
when :gml
|
96
|
+
georss_gml_representation(options)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#georss simple representation
|
101
|
+
def georss_simple_representation(options = {}) #:nodoc:
|
102
|
+
georss_ns = options[:georss_ns] || "georss"
|
103
|
+
geom_attr = options[:geom_attr]
|
104
|
+
"<#{georss_ns}:box#{geom_attr}>#{lower_corner.y} #{lower_corner.x} #{upper_corner.y} #{upper_corner.x}</#{georss_ns}:box>\n"
|
105
|
+
end
|
106
|
+
|
107
|
+
#georss w3c representation : outputs the first point of the line
|
108
|
+
def georss_w3cgeo_representation(options = {}) #:nodoc:
|
109
|
+
w3cgeo_ns = options[:w3cgeo_ns] || "geo"
|
110
|
+
point = self.center
|
111
|
+
"<#{w3cgeo_ns}:lat>#{point.y}</#{w3cgeo_ns}:lat>\n<#{w3cgeo_ns}:long>#{point.x}</#{w3cgeo_ns}:long>\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
#georss gml representation
|
115
|
+
def georss_gml_representation(options = {}) #:nodoc:
|
116
|
+
georss_ns = options[:georss_ns] || "georss"
|
117
|
+
gml_ns = options[:gml_ns] || "gml"
|
118
|
+
result = "<#{georss_ns}:where>\n<#{gml_ns}:Envelope>\n"
|
119
|
+
result += "<#{gml_ns}:LowerCorner>" + "#{lower_corner.y} #{lower_corner.x}" + "</#{gml_ns}:LowerCorner>"
|
120
|
+
result += "<#{gml_ns}:UpperCorner>" + "#{upper_corner.y} #{upper_corner.x}" + "</#{gml_ns}:UpperCorner>"
|
121
|
+
result += "</#{gml_ns}:Envelope>\n</#{georss_ns}:where>\n"
|
122
|
+
end
|
123
|
+
|
124
|
+
#Sends back a latlonaltbox
|
125
|
+
def as_kml(options = {})
|
126
|
+
geom_data = ""
|
127
|
+
geom_data = "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
|
128
|
+
|
129
|
+
allow_z = with_z && (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
|
130
|
+
|
131
|
+
kml_representation(options.merge(:geom_data => geom_data,:allow_z => allow_z))
|
132
|
+
end
|
133
|
+
|
134
|
+
def kml_representation(options = {})#:nodoc:
|
135
|
+
result = "<LatLonAltBox>\n"
|
136
|
+
result += options[:geom_data]
|
137
|
+
result += "<north>#{upper_corner.y}</north>\n"
|
138
|
+
result += "<south>#{lower_corner.y}</south>\n"
|
139
|
+
result += "<east>#{upper_corner.x}</east>\n"
|
140
|
+
result += "<west>#{lower_corner.x}</west>\n"
|
141
|
+
|
142
|
+
if with_z
|
143
|
+
result += "<minAltitude>#{lower_corner.z}</minAltitude>"
|
144
|
+
result += "<maxAltitude>#{upper_corner.z}</maxAltitude>"
|
145
|
+
end
|
146
|
+
|
147
|
+
result += "</LatLonAltBox>\n"
|
148
|
+
end
|
149
|
+
|
150
|
+
#Creates a new envelope. Accept an array of 2 points as argument
|
151
|
+
def self.from_points(points,srid=@@default_srid,with_z=false)
|
152
|
+
raise "Not an array" unless points.class == Array
|
153
|
+
e = Envelope.new(srid,with_z)
|
154
|
+
e.lower_corner, e.upper_corner = points
|
155
|
+
e
|
156
|
+
end
|
157
|
+
|
158
|
+
#Creates a new envelope. Accept a sequence of point coordinates as argument : ((x,y),(x,y))
|
159
|
+
def self.from_coordinates(points,srid=@@default_srid,with_z=false)
|
160
|
+
e = Envelope.new(srid,with_z)
|
161
|
+
e.lower_corner, e.upper_corner = points.collect{|point_coords| Point.from_coordinates(point_coords,srid,with_z)}
|
162
|
+
e
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'geo_ruby/base/point'
|
2
|
+
require 'geo_ruby/base/line_string'
|
3
|
+
require 'geo_ruby/base/linear_ring'
|
4
|
+
require 'geo_ruby/base/polygon'
|
5
|
+
require 'geo_ruby/base/multi_point'
|
6
|
+
require 'geo_ruby/base/multi_line_string'
|
7
|
+
require 'geo_ruby/base/multi_polygon'
|
8
|
+
require 'geo_ruby/base/geometry_collection'
|
9
|
+
|
10
|
+
module GeoRuby
|
11
|
+
module Base
|
12
|
+
|
13
|
+
#Raised when an error in the EWKB string is detected
|
14
|
+
class EWKBFormatError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
#Parses EWKB strings and notifies of events (such as the beginning of the definition of geometry, the value of the SRID...) the factory passed as argument to the constructor.
|
18
|
+
#
|
19
|
+
#=Example
|
20
|
+
# factory = GeometryFactory::new
|
21
|
+
# ewkb_parser = EWKBParser::new(factory)
|
22
|
+
# ewkb_parser.parse(<EWKB String>)
|
23
|
+
# geometry = @factory.geometry
|
24
|
+
#
|
25
|
+
#You can also use directly the static method Geometry.from_ewkb
|
26
|
+
class EWKBParser
|
27
|
+
|
28
|
+
def initialize(factory)
|
29
|
+
@factory = factory
|
30
|
+
@parse_options ={
|
31
|
+
1 => method(:parse_point),
|
32
|
+
2 => method(:parse_line_string),
|
33
|
+
3 => method(:parse_polygon),
|
34
|
+
4 => method(:parse_multi_point),
|
35
|
+
5 => method(:parse_multi_line_string),
|
36
|
+
6 => method(:parse_multi_polygon),
|
37
|
+
7 => method(:parse_geometry_collection)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
#Parses the ewkb string passed as argument and notifies the factory of events
|
42
|
+
def parse(ewkb)
|
43
|
+
@factory.reset
|
44
|
+
@unpack_structure=UnpackStructure::new(ewkb)
|
45
|
+
@with_z = false
|
46
|
+
@with_m = false
|
47
|
+
parse_geometry
|
48
|
+
@unpack_structure.done
|
49
|
+
@srid=nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def parse_geometry
|
54
|
+
@unpack_structure.endianness=@unpack_structure.read_byte
|
55
|
+
@geometry_type = @unpack_structure.read_uint
|
56
|
+
|
57
|
+
if (@geometry_type & Z_MASK) != 0
|
58
|
+
@with_z=true
|
59
|
+
@geometry_type = @geometry_type & ~Z_MASK
|
60
|
+
end
|
61
|
+
if (@geometry_type & M_MASK) != 0
|
62
|
+
@with_m=true
|
63
|
+
@geometry_type = @geometry_type & ~M_MASK
|
64
|
+
end
|
65
|
+
if (@geometry_type & SRID_MASK) != 0
|
66
|
+
@srid = @unpack_structure.read_uint
|
67
|
+
@geometry_type = @geometry_type & ~SRID_MASK
|
68
|
+
else
|
69
|
+
#to manage multi geometries : the srid is not present in sub_geometries, therefore we take the srid of the parent ; if it is the root, we take the default srid
|
70
|
+
@srid= @srid || @@default_srid
|
71
|
+
end
|
72
|
+
|
73
|
+
if @parse_options.has_key? @geometry_type
|
74
|
+
@parse_options[@geometry_type].call
|
75
|
+
else
|
76
|
+
raise EWKBFormatError::new("Unknown geometry type")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_geometry_collection
|
81
|
+
parse_multi_geometries(GeometryCollection)
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_multi_polygon
|
85
|
+
parse_multi_geometries(MultiPolygon)
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_multi_line_string
|
89
|
+
parse_multi_geometries(MultiLineString)
|
90
|
+
end
|
91
|
+
|
92
|
+
def parse_multi_point
|
93
|
+
parse_multi_geometries(MultiPoint)
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_multi_geometries(geometry_type)
|
97
|
+
@factory.begin_geometry(geometry_type,@srid)
|
98
|
+
num_geometries = @unpack_structure.read_uint
|
99
|
+
1.upto(num_geometries) { parse_geometry }
|
100
|
+
@factory.end_geometry(@with_z,@with_m)
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_polygon
|
104
|
+
@factory.begin_geometry(Polygon,@srid)
|
105
|
+
num_linear_rings = @unpack_structure.read_uint
|
106
|
+
1.upto(num_linear_rings) {parse_linear_ring}
|
107
|
+
@factory.end_geometry(@with_z,@with_m)
|
108
|
+
end
|
109
|
+
|
110
|
+
def parse_linear_ring
|
111
|
+
parse_point_list(LinearRing)
|
112
|
+
end
|
113
|
+
|
114
|
+
def parse_line_string
|
115
|
+
parse_point_list(LineString)
|
116
|
+
end
|
117
|
+
|
118
|
+
#used to parse line_strings and linear_rings
|
119
|
+
def parse_point_list(geometry_type)
|
120
|
+
@factory.begin_geometry(geometry_type,@srid)
|
121
|
+
num_points = @unpack_structure.read_uint
|
122
|
+
1.upto(num_points) {parse_point}
|
123
|
+
@factory.end_geometry(@with_z,@with_m)
|
124
|
+
end
|
125
|
+
|
126
|
+
def parse_point
|
127
|
+
@factory.begin_geometry(Point,@srid)
|
128
|
+
x = @unpack_structure.read_double
|
129
|
+
y = @unpack_structure.read_double
|
130
|
+
if ! (@with_z or @with_m) #most common case probably
|
131
|
+
@factory.add_point_x_y(x,y)
|
132
|
+
elsif @with_m and @with_z
|
133
|
+
z = @unpack_structure.read_double
|
134
|
+
m = @unpack_structure.read_double
|
135
|
+
@factory.add_point_x_y_z_m(x,y,z,m)
|
136
|
+
elsif @with_z
|
137
|
+
z = @unpack_structure.read_double
|
138
|
+
@factory.add_point_x_y_z(x,y,z)
|
139
|
+
else
|
140
|
+
m = @unpack_structure.read_double
|
141
|
+
@factory.add_point_x_y_m(x,y,m)
|
142
|
+
end
|
143
|
+
|
144
|
+
@factory.end_geometry(@with_z,@with_m)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
#Parses HexEWKB strings. In reality, it just transforms the HexEWKB string into the equivalent EWKB string and lets the EWKBParser do the actual parsing.
|
149
|
+
class HexEWKBParser < EWKBParser
|
150
|
+
def initialize(factory)
|
151
|
+
super(factory)
|
152
|
+
end
|
153
|
+
#parses an HexEWKB string
|
154
|
+
def parse(hexewkb)
|
155
|
+
super(decode_hex(hexewkb))
|
156
|
+
end
|
157
|
+
#transforms a HexEWKB string into an EWKB string
|
158
|
+
def decode_hex(hexewkb)
|
159
|
+
result=""
|
160
|
+
num_bytes = (hexewkb.size + 1) / 2
|
161
|
+
0.upto(num_bytes-1) do |i|
|
162
|
+
result << hexewkb[i*2,2].hex
|
163
|
+
end
|
164
|
+
result
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class HexEWKBParser < EWKBParser
|
169
|
+
#transforms a HexEWKB string into an EWKB string
|
170
|
+
# Patched for speedup
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
class UnpackStructure #:nodoc:
|
175
|
+
NDR=1
|
176
|
+
XDR=0
|
177
|
+
def initialize(ewkb)
|
178
|
+
@position=0
|
179
|
+
@ewkb=ewkb
|
180
|
+
end
|
181
|
+
def done
|
182
|
+
raise EWKBFormatError::new("Trailing data") if @position != @ewkb.length
|
183
|
+
end
|
184
|
+
def read_double
|
185
|
+
i=@position
|
186
|
+
@position += 8
|
187
|
+
packed_double = @ewkb[i...@position]
|
188
|
+
raise EWKBFormatError::new("Truncated data") if packed_double.nil? or packed_double.length < 8
|
189
|
+
packed_double.unpack(@double_mark)[0]
|
190
|
+
end
|
191
|
+
def read_uint
|
192
|
+
i=@position
|
193
|
+
@position += 4
|
194
|
+
packed_uint = @ewkb[i...@position]
|
195
|
+
raise EWKBFormatError::new("Truncated data") if packed_uint.nil? or packed_uint.length < 4
|
196
|
+
packed_uint.unpack(@uint_mark)[0]
|
197
|
+
end
|
198
|
+
def read_byte
|
199
|
+
i = @position
|
200
|
+
@position += 1
|
201
|
+
packed_byte = @ewkb[i...@position]
|
202
|
+
raise EWKBFormatError::new("Truncated data") if packed_byte.nil? or packed_byte.length < 1
|
203
|
+
packed_byte.unpack("C")[0]
|
204
|
+
end
|
205
|
+
def endianness=(byte_order)
|
206
|
+
if(byte_order == NDR)
|
207
|
+
@uint_mark="V"
|
208
|
+
@double_mark="E"
|
209
|
+
elsif(byte_order == XDR)
|
210
|
+
@uint_mark="N"
|
211
|
+
@double_mark="G"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|