schleyfox-rgeo 0.2.5
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.rdoc +199 -0
- data/README.rdoc +172 -0
- data/Spatial_Programming_With_RGeo.rdoc +440 -0
- data/Version +1 -0
- data/ext/geos_c_impl/extconf.rb +84 -0
- data/ext/geos_c_impl/factory.c +468 -0
- data/ext/geos_c_impl/factory.h +224 -0
- data/ext/geos_c_impl/geometry.c +705 -0
- data/ext/geos_c_impl/geometry.h +55 -0
- data/ext/geos_c_impl/geometry_collection.c +482 -0
- data/ext/geos_c_impl/geometry_collection.h +69 -0
- data/ext/geos_c_impl/line_string.c +509 -0
- data/ext/geos_c_impl/line_string.h +64 -0
- data/ext/geos_c_impl/main.c +70 -0
- data/ext/geos_c_impl/point.c +193 -0
- data/ext/geos_c_impl/point.h +62 -0
- data/ext/geos_c_impl/polygon.c +265 -0
- data/ext/geos_c_impl/polygon.h +66 -0
- data/ext/geos_c_impl/preface.h +50 -0
- data/ext/proj4_c_impl/extconf.rb +88 -0
- data/ext/proj4_c_impl/main.c +271 -0
- data/lib/rgeo.rb +124 -0
- data/lib/rgeo/cartesian.rb +60 -0
- data/lib/rgeo/cartesian/analysis.rb +118 -0
- data/lib/rgeo/cartesian/bounding_box.rb +337 -0
- data/lib/rgeo/cartesian/calculations.rb +161 -0
- data/lib/rgeo/cartesian/factory.rb +209 -0
- data/lib/rgeo/cartesian/feature_classes.rb +173 -0
- data/lib/rgeo/cartesian/feature_methods.rb +106 -0
- data/lib/rgeo/cartesian/interface.rb +150 -0
- data/lib/rgeo/coord_sys.rb +79 -0
- data/lib/rgeo/coord_sys/cs/entities.rb +1524 -0
- data/lib/rgeo/coord_sys/cs/factories.rb +208 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +308 -0
- data/lib/rgeo/coord_sys/proj4.rb +312 -0
- data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +194 -0
- data/lib/rgeo/coord_sys/srs_database/interface.rb +165 -0
- data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +188 -0
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +108 -0
- data/lib/rgeo/coord_sys/srs_database/url_reader.rb +108 -0
- data/lib/rgeo/error.rb +63 -0
- data/lib/rgeo/feature.rb +88 -0
- data/lib/rgeo/feature/curve.rb +156 -0
- data/lib/rgeo/feature/factory.rb +332 -0
- data/lib/rgeo/feature/factory_generator.rb +138 -0
- data/lib/rgeo/feature/geometry.rb +614 -0
- data/lib/rgeo/feature/geometry_collection.rb +129 -0
- data/lib/rgeo/feature/line.rb +66 -0
- data/lib/rgeo/feature/line_string.rb +102 -0
- data/lib/rgeo/feature/linear_ring.rb +66 -0
- data/lib/rgeo/feature/multi_curve.rb +113 -0
- data/lib/rgeo/feature/multi_line_string.rb +66 -0
- data/lib/rgeo/feature/multi_point.rb +73 -0
- data/lib/rgeo/feature/multi_polygon.rb +97 -0
- data/lib/rgeo/feature/multi_surface.rb +116 -0
- data/lib/rgeo/feature/point.rb +120 -0
- data/lib/rgeo/feature/polygon.rb +141 -0
- data/lib/rgeo/feature/surface.rb +122 -0
- data/lib/rgeo/feature/types.rb +305 -0
- data/lib/rgeo/geographic.rb +75 -0
- data/lib/rgeo/geographic/factory.rb +287 -0
- data/lib/rgeo/geographic/interface.rb +410 -0
- data/lib/rgeo/geographic/proj4_projector.rb +98 -0
- data/lib/rgeo/geographic/projected_feature_classes.rb +213 -0
- data/lib/rgeo/geographic/projected_feature_methods.rb +228 -0
- data/lib/rgeo/geographic/projected_window.rb +467 -0
- data/lib/rgeo/geographic/simple_mercator_projector.rb +157 -0
- data/lib/rgeo/geographic/spherical_feature_classes.rb +212 -0
- data/lib/rgeo/geographic/spherical_feature_methods.rb +97 -0
- data/lib/rgeo/geographic/spherical_math.rb +206 -0
- data/lib/rgeo/geos.rb +72 -0
- data/lib/rgeo/geos/factory.rb +301 -0
- data/lib/rgeo/geos/impl_additions.rb +76 -0
- data/lib/rgeo/geos/interface.rb +139 -0
- data/lib/rgeo/geos/zm_factory.rb +275 -0
- data/lib/rgeo/geos/zm_impl.rb +432 -0
- data/lib/rgeo/impl_helper.rb +53 -0
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +235 -0
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +85 -0
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +197 -0
- data/lib/rgeo/impl_helper/basic_point_methods.rb +138 -0
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +121 -0
- data/lib/rgeo/impl_helper/math.rb +50 -0
- data/lib/rgeo/version.rb +52 -0
- data/lib/rgeo/wkrep.rb +72 -0
- data/lib/rgeo/wkrep/wkb_generator.rb +267 -0
- data/lib/rgeo/wkrep/wkb_parser.rb +315 -0
- data/lib/rgeo/wkrep/wkt_generator.rb +275 -0
- data/lib/rgeo/wkrep/wkt_parser.rb +496 -0
- data/test/common/geometry_collection_tests.rb +238 -0
- data/test/common/line_string_tests.rb +324 -0
- data/test/common/multi_line_string_tests.rb +209 -0
- data/test/common/multi_point_tests.rb +201 -0
- data/test/common/multi_polygon_tests.rb +208 -0
- data/test/common/point_tests.rb +331 -0
- data/test/common/polygon_tests.rb +232 -0
- data/test/coord_sys/tc_active_record_table.rb +102 -0
- data/test/coord_sys/tc_ogc_cs.rb +356 -0
- data/test/coord_sys/tc_proj4.rb +138 -0
- data/test/coord_sys/tc_proj4_srs_data.rb +76 -0
- data/test/coord_sys/tc_sr_org.rb +70 -0
- data/test/coord_sys/tc_url_reader.rb +82 -0
- data/test/geos/tc_factory.rb +91 -0
- data/test/geos/tc_geometry_collection.rb +62 -0
- data/test/geos/tc_line_string.rb +62 -0
- data/test/geos/tc_misc.rb +72 -0
- data/test/geos/tc_multi_line_string.rb +62 -0
- data/test/geos/tc_multi_point.rb +62 -0
- data/test/geos/tc_multi_polygon.rb +63 -0
- data/test/geos/tc_point.rb +86 -0
- data/test/geos/tc_polygon.rb +86 -0
- data/test/geos/tc_zmfactory.rb +85 -0
- data/test/projected_geographic/tc_geometry_collection.rb +62 -0
- data/test/projected_geographic/tc_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_point.rb +62 -0
- data/test/projected_geographic/tc_multi_polygon.rb +63 -0
- data/test/projected_geographic/tc_point.rb +93 -0
- data/test/projected_geographic/tc_polygon.rb +62 -0
- data/test/simple_cartesian/tc_calculations.rb +145 -0
- data/test/simple_cartesian/tc_geometry_collection.rb +69 -0
- data/test/simple_cartesian/tc_line_string.rb +70 -0
- data/test/simple_cartesian/tc_multi_line_string.rb +67 -0
- data/test/simple_cartesian/tc_multi_point.rb +67 -0
- data/test/simple_cartesian/tc_multi_polygon.rb +70 -0
- data/test/simple_cartesian/tc_point.rb +91 -0
- data/test/simple_cartesian/tc_polygon.rb +67 -0
- data/test/simple_mercator/tc_geometry_collection.rb +62 -0
- data/test/simple_mercator/tc_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_point.rb +62 -0
- data/test/simple_mercator/tc_multi_polygon.rb +63 -0
- data/test/simple_mercator/tc_point.rb +93 -0
- data/test/simple_mercator/tc_polygon.rb +62 -0
- data/test/simple_mercator/tc_window.rb +219 -0
- data/test/spherical_geographic/tc_calculations.rb +203 -0
- data/test/spherical_geographic/tc_geometry_collection.rb +70 -0
- data/test/spherical_geographic/tc_line_string.rb +70 -0
- data/test/spherical_geographic/tc_multi_line_string.rb +67 -0
- data/test/spherical_geographic/tc_multi_point.rb +67 -0
- data/test/spherical_geographic/tc_multi_polygon.rb +70 -0
- data/test/spherical_geographic/tc_point.rb +100 -0
- data/test/spherical_geographic/tc_polygon.rb +67 -0
- data/test/tc_cartesian_analysis.rb +107 -0
- data/test/tc_oneoff.rb +63 -0
- data/test/wkrep/tc_wkb_generator.rb +249 -0
- data/test/wkrep/tc_wkb_parser.rb +353 -0
- data/test/wkrep/tc_wkt_generator.rb +362 -0
- data/test/wkrep/tc_wkt_parser.rb +480 -0
- metadata +267 -0
@@ -0,0 +1,315 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Well-known binary parser for RGeo
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module WKRep
|
40
|
+
|
41
|
+
|
42
|
+
# This class provides the functionality of parsing a geometry from
|
43
|
+
# WKB (well-known binary) format. You may also customize the parser
|
44
|
+
# to recognize PostGIS EWKB extensions to the input, or Simple
|
45
|
+
# Features Specification 1.2 extensions for Z and M coordinates.
|
46
|
+
#
|
47
|
+
# To use this class, create an instance with the desired settings and
|
48
|
+
# customizations, and call the parse method.
|
49
|
+
#
|
50
|
+
# === Configuration options
|
51
|
+
#
|
52
|
+
# You must provide each parser with an RGeo::Feature::FactoryGenerator.
|
53
|
+
# It should understand the configuration options <tt>:srid</tt>,
|
54
|
+
# <tt>:has_z_coordinate</tt>, and <tt>:has_m_coordinate</tt>.
|
55
|
+
# You may also pass a specific RGeo::Feature::Factory, or nil to
|
56
|
+
# specify the default Cartesian FactoryGenerator.
|
57
|
+
#
|
58
|
+
# The following additional options are recognized. These can be passed
|
59
|
+
# to the constructor, or set on the object afterwards.
|
60
|
+
#
|
61
|
+
# [<tt>:support_ewkb</tt>]
|
62
|
+
# Activate support for PostGIS EWKB type codes, which use high
|
63
|
+
# order bits in the type code to signal the presence of Z, M, and
|
64
|
+
# SRID values in the data. Default is false.
|
65
|
+
# [<tt>:support_wkb12</tt>]
|
66
|
+
# Activate support for SFS 1.2 extensions to the type codes, which
|
67
|
+
# use values greater than 1000 to signal the presence of Z and M
|
68
|
+
# values in the data. SFS 1.2 types such as triangle, tin, and
|
69
|
+
# polyhedralsurface are NOT yet supported. Default is false.
|
70
|
+
# [<tt>:ignore_extra_bytes</tt>]
|
71
|
+
# If true, extra bytes at the end of the data are ignored. If
|
72
|
+
# false (the default), extra bytes will trigger a parse error.
|
73
|
+
# [<tt>:default_srid</tt>]
|
74
|
+
# A SRID to pass to the factory generator if no SRID is present in
|
75
|
+
# the input. Defaults to nil (i.e. don't specify a SRID).
|
76
|
+
|
77
|
+
class WKBParser
|
78
|
+
|
79
|
+
|
80
|
+
# Create and configure a WKB parser. See the WKBParser
|
81
|
+
# documentation for the options that can be passed.
|
82
|
+
|
83
|
+
def initialize(factory_generator_=nil, opts_={})
|
84
|
+
self.factory_generator = factory_generator_
|
85
|
+
@support_ewkb = opts_[:support_ewkb] ? true : false
|
86
|
+
@support_wkb12 = opts_[:support_wkb12] ? true : false
|
87
|
+
@ignore_extra_bytes = opts_[:ignore_extra_bytes] ? true : false
|
88
|
+
@default_srid = opts_[:default_srid]
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Returns the factory generator. See WKBParser for details.
|
93
|
+
def factory_generator
|
94
|
+
@factory_generator
|
95
|
+
end
|
96
|
+
|
97
|
+
# If this parser was given an exact factory, returns it; otherwise
|
98
|
+
# returns nil.
|
99
|
+
def exact_factory
|
100
|
+
@exact_factory
|
101
|
+
end
|
102
|
+
|
103
|
+
# Sets the factory_generator. See WKBParser for details.
|
104
|
+
def factory_generator=(value_)
|
105
|
+
if value_.kind_of?(Feature::Factory::Instance)
|
106
|
+
@factory_generator = Feature::FactoryGenerator.single(value_)
|
107
|
+
@exact_factory = value_
|
108
|
+
elsif value_.respond_to?(:call)
|
109
|
+
@factory_generator = value_
|
110
|
+
@exact_factory = nil
|
111
|
+
else
|
112
|
+
@factory_generator = Cartesian.method(:preferred_factory)
|
113
|
+
@exact_factory = nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Sets the factory_generator to the given block.
|
118
|
+
# See WKBParser for details.
|
119
|
+
def to_generate_factory(&block_)
|
120
|
+
@factory_generator = block_
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns true if this parser supports EWKB.
|
124
|
+
# See WKBParser for details.
|
125
|
+
def support_ewkb?
|
126
|
+
@support_ewkb
|
127
|
+
end
|
128
|
+
|
129
|
+
# Sets the the support_ewkb flag. See WKBParser for details.
|
130
|
+
def support_ewkb=(value_)
|
131
|
+
@support_ewkb = value_ ? true : false
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns true if this parser supports SFS 1.2 extensions.
|
135
|
+
# See WKBParser for details.
|
136
|
+
def support_wkb12?
|
137
|
+
@support_wkb12
|
138
|
+
end
|
139
|
+
|
140
|
+
# Sets the the support_wkb12 flag. See WKBParser for details.
|
141
|
+
def support_wkb12=(value_)
|
142
|
+
@support_wkb12 = value_ ? true : false
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns true if this parser ignores extra bytes.
|
146
|
+
# See WKBParser for details.
|
147
|
+
def ignore_extra_bytes?
|
148
|
+
@ignore_extra_bytes
|
149
|
+
end
|
150
|
+
|
151
|
+
# Sets the the ignore_extra_bytes flag. See WKBParser for details.
|
152
|
+
def ignore_extra_bytes=(value_)
|
153
|
+
@ignore_extra_bytes = value_ ? true : false
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# Parse the given hex string, and return a geometry object.
|
158
|
+
|
159
|
+
def parse_hex(str_)
|
160
|
+
parse([str_].pack('H*'))
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# Parse the given binary data, and return a geometry object.
|
165
|
+
|
166
|
+
def parse(data_)
|
167
|
+
@cur_has_z = nil
|
168
|
+
@cur_has_m = nil
|
169
|
+
@cur_srid = nil
|
170
|
+
@cur_dims = 2
|
171
|
+
@cur_factory = nil
|
172
|
+
begin
|
173
|
+
_start_scanner(data_)
|
174
|
+
obj_ = _parse_object(false)
|
175
|
+
unless @ignore_extra_bytes
|
176
|
+
bytes_ = _bytes_remaining
|
177
|
+
if bytes_ > 0
|
178
|
+
raise Error::ParseError, "Found #{bytes_} extra bytes at the end of the stream."
|
179
|
+
end
|
180
|
+
end
|
181
|
+
ensure
|
182
|
+
_clean_scanner
|
183
|
+
end
|
184
|
+
obj_
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def _parse_object(contained_) # :nodoc:
|
189
|
+
little_endian_ = _get_byte == 1
|
190
|
+
type_code_ = _get_integer(little_endian_)
|
191
|
+
has_z_ = false
|
192
|
+
has_m_ = false
|
193
|
+
srid_ = contained_ ? nil : @default_srid
|
194
|
+
if @support_ewkb
|
195
|
+
has_z_ ||= type_code_ & 0x80000000 != 0
|
196
|
+
has_m_ ||= type_code_ & 0x40000000 != 0
|
197
|
+
srid_ = _get_integer(little_endian_) if type_code_ & 0x20000000 != 0
|
198
|
+
type_code_ &= 0x0fffffff
|
199
|
+
end
|
200
|
+
if @support_wkb12
|
201
|
+
has_z_ ||= (type_code_ / 1000) & 1 != 0
|
202
|
+
has_m_ ||= (type_code_ / 1000) & 2 != 0
|
203
|
+
type_code_ %= 1000
|
204
|
+
end
|
205
|
+
if contained_
|
206
|
+
if contained_ != true && contained_ != type_code_
|
207
|
+
raise Error::ParseError, "Enclosed type=#{type_code_} is different from container constraint #{contained_}"
|
208
|
+
end
|
209
|
+
if has_z_ != @cur_has_z
|
210
|
+
raise Error::ParseError, "Enclosed hasZ=#{has_z_} is different from toplevel hasZ=#{@cur_has_z}"
|
211
|
+
end
|
212
|
+
if has_m_ != @cur_has_m
|
213
|
+
raise Error::ParseError, "Enclosed hasM=#{has_m_} is different from toplevel hasM=#{@cur_has_m}"
|
214
|
+
end
|
215
|
+
if srid_ && srid_ != @cur_srid
|
216
|
+
raise Error::ParseError, "Enclosed SRID #{srid_} is different from toplevel srid #{@cur_srid || '(unspecified)'}"
|
217
|
+
end
|
218
|
+
else
|
219
|
+
@cur_has_z = has_z_
|
220
|
+
@cur_has_m = has_m_
|
221
|
+
@cur_dims = 2 + (@cur_has_z ? 1 : 0) + (@cur_has_m ? 1 : 0)
|
222
|
+
@cur_srid = srid_
|
223
|
+
@cur_factory = @factory_generator.call(:srid => @cur_srid, :has_z_coordinate => has_z_, :has_m_coordinate => has_m_)
|
224
|
+
if @cur_has_z && !@cur_factory.property(:has_z_coordinate)
|
225
|
+
raise Error::ParseError, "Data has Z coordinates but the factory doesn't have Z coordinates"
|
226
|
+
end
|
227
|
+
if @cur_has_m && !@cur_factory.property(:has_m_coordinate)
|
228
|
+
raise Error::ParseError, "Data has M coordinates but the factory doesn't have M coordinates"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
case type_code_
|
232
|
+
when 1
|
233
|
+
coords_ = _get_doubles(little_endian_, @cur_dims)
|
234
|
+
@cur_factory.point(*coords_)
|
235
|
+
when 2
|
236
|
+
_parse_line_string(little_endian_)
|
237
|
+
when 3
|
238
|
+
interior_rings_ = (1.._get_integer(little_endian_)).map{ _parse_line_string(little_endian_) }
|
239
|
+
exterior_ring_ = interior_rings_.shift || @cur_factory.linear_ring([])
|
240
|
+
@cur_factory.polygon(exterior_ring_, interior_rings_)
|
241
|
+
when 4
|
242
|
+
@cur_factory.multi_point((1.._get_integer(little_endian_)).map{ _parse_object(1) })
|
243
|
+
when 5
|
244
|
+
@cur_factory.multi_line_string((1.._get_integer(little_endian_)).map{ _parse_object(2) })
|
245
|
+
when 6
|
246
|
+
@cur_factory.multi_polygon((1.._get_integer(little_endian_)).map{ _parse_object(3) })
|
247
|
+
when 7
|
248
|
+
@cur_factory.collection((1.._get_integer(little_endian_)).map{ _parse_object(true) })
|
249
|
+
else
|
250
|
+
raise Error::ParseError, "Unknown type value: #{type_code_}."
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def _parse_line_string(little_endian_) # :nodoc:
|
256
|
+
count_ = _get_integer(little_endian_)
|
257
|
+
coords_ = _get_doubles(little_endian_, @cur_dims * count_)
|
258
|
+
@cur_factory.line_string((0...count_).map{ |i_| @cur_factory.point(*coords_[@cur_dims*i_,@cur_dims]) })
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
def _start_scanner(data_) # :nodoc:
|
263
|
+
@_data = data_
|
264
|
+
@_len = data_.length
|
265
|
+
@_pos = 0
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
def _clean_scanner # :nodoc:
|
270
|
+
@_data = nil
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def _bytes_remaining # :nodoc:
|
275
|
+
@_len - @_pos
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
def _get_byte # :nodoc:
|
280
|
+
if @_pos + 1 > @_len
|
281
|
+
raise Error::ParseError, "Not enough bytes left to fulfill 1 byte"
|
282
|
+
end
|
283
|
+
str_ = @_data[@_pos, 1]
|
284
|
+
@_pos += 1
|
285
|
+
str_.unpack("C").first
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
def _get_integer(little_endian_) # :nodoc:
|
290
|
+
if @_pos + 4 > @_len
|
291
|
+
raise Error::ParseError, "Not enough bytes left to fulfill 1 integer"
|
292
|
+
end
|
293
|
+
str_ = @_data[@_pos, 4]
|
294
|
+
@_pos += 4
|
295
|
+
str_.unpack("#{little_endian_ ? 'V' : 'N'}").first
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
def _get_doubles(little_endian_, count_) # :nodoc:
|
300
|
+
len_ = 8 * count_
|
301
|
+
if @_pos + len_ > @_len
|
302
|
+
raise Error::ParseError, "Not enough bytes left to fulfill #{count_} doubles"
|
303
|
+
end
|
304
|
+
str_ = @_data[@_pos, len_]
|
305
|
+
@_pos += len_
|
306
|
+
str_.unpack("#{little_endian_ ? 'E' : 'G'}*")
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Well-known text generator for RGeo
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module WKRep
|
40
|
+
|
41
|
+
|
42
|
+
# This class provides the functionality of serializing a geometry as
|
43
|
+
# WKT (well-known text) format. You may also customize the serializer
|
44
|
+
# to generate PostGIS EWKT extensions to the output, or to follow the
|
45
|
+
# Simple Features Specification 1.2 extensions for Z and M.
|
46
|
+
#
|
47
|
+
# To use this class, create an instance with the desired settings and
|
48
|
+
# customizations, and call the generate method.
|
49
|
+
#
|
50
|
+
# === Configuration options
|
51
|
+
#
|
52
|
+
# The following options are recognized. These can be passed to the
|
53
|
+
# constructor, or set on the object afterwards.
|
54
|
+
#
|
55
|
+
# [<tt>:tag_format</tt>]
|
56
|
+
# The format for tags. Possible values are <tt>:wkt11</tt>,
|
57
|
+
# indicating SFS 1.1 WKT (i.e. no Z or M markers in the tags) but
|
58
|
+
# with Z and/or M values added in if they are present;
|
59
|
+
# <tt>:wkt11_strict</tt>, indicating SFS 1.1 WKT with Z and M
|
60
|
+
# dropped from the output (since WKT strictly does not support
|
61
|
+
# the Z or M dimensions); <tt>:ewkt</tt>, indicating the PostGIS
|
62
|
+
# EWKT extensions (i.e. "M" appended to tag names if M but not
|
63
|
+
# Z is present); or <tt>:wkt12</tt>, indicating SFS 1.2 WKT
|
64
|
+
# tags that indicate the presence of Z and M in a separate token.
|
65
|
+
# Default is <tt>:wkt11</tt>.
|
66
|
+
# [<tt>:emit_ewkt_srid</tt>]
|
67
|
+
# If true, embed the SRID of the toplevel geometry. Available only
|
68
|
+
# if <tt>:type_format</tt> is <tt>:ewkt</tt>. Default is false.
|
69
|
+
# [<tt>:square_brackets</tt>]
|
70
|
+
# If true, uses square brackets rather than parentheses.
|
71
|
+
# Default is false.
|
72
|
+
# [<tt>:convert_case</tt>]
|
73
|
+
# Possible values are <tt>:upper</tt>, which changes all letters
|
74
|
+
# in the output to ALL CAPS; <tt>:lower</tt>, which changes all
|
75
|
+
# letters to lower case; or nil, indicating no case changes from
|
76
|
+
# the default (which is not specified exactly, but is chosen by the
|
77
|
+
# generator to emphasize readability.) Default is nil.
|
78
|
+
|
79
|
+
class WKTGenerator
|
80
|
+
|
81
|
+
|
82
|
+
# Create and configure a WKT generator. See the WKTGenerator
|
83
|
+
# documentation for the options that can be passed.
|
84
|
+
|
85
|
+
def initialize(opts_={})
|
86
|
+
@tag_format = opts_[:tag_format] || :wkt11
|
87
|
+
@emit_ewkt_srid = opts_[:emit_ewkt_srid] ? true : false if @tag_format == :ewkt
|
88
|
+
@square_brackets = opts_[:square_brackets] ? true : false
|
89
|
+
@convert_case = opts_[:convert_case]
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# Returns the format for type tags. See WKTGenerator for details.
|
94
|
+
def tag_format
|
95
|
+
@tag_format
|
96
|
+
end
|
97
|
+
|
98
|
+
# Sets the format for type tags. See WKTGenerator for details.
|
99
|
+
def tag_format=(value_)
|
100
|
+
@tag_format = value_
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns whether SRID is embedded. See WKTGenerator for details.
|
104
|
+
def emit_ewkt_srid?
|
105
|
+
@emit_ewkt_srid
|
106
|
+
end
|
107
|
+
|
108
|
+
# Sets whether SRID is embedded. Available only when the tag_format
|
109
|
+
# is <tt>:ewkt</tt>. See WKTGenerator for details.
|
110
|
+
def emit_ewkt_srid=(value_)
|
111
|
+
@emit_ewkt_srid = @type_format == :ewkt && value_
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns whether square brackets rather than parens are output.
|
115
|
+
# See WKTGenerator for details.
|
116
|
+
def square_brackets?
|
117
|
+
@square_brackets
|
118
|
+
end
|
119
|
+
|
120
|
+
# Sets whether square brackets rather than parens are output.
|
121
|
+
# See WKTGenerator for details.
|
122
|
+
def square_brackets=(value_)
|
123
|
+
@square_brackets = value_ ? true : false
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the case for output. See WKTGenerator for details.
|
127
|
+
def convert_case
|
128
|
+
@convert_case
|
129
|
+
end
|
130
|
+
|
131
|
+
# Sets the case for output. See WKTGenerator for details.
|
132
|
+
def convert_case=(value_)
|
133
|
+
@convert_case = value_
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# Generate and return the WKT format for the given geometry object,
|
138
|
+
# according to the current settings.
|
139
|
+
|
140
|
+
def generate(obj_)
|
141
|
+
@begin_bracket = @square_brackets ? '[' : '('
|
142
|
+
@end_bracket = @square_brackets ? ']' : ')'
|
143
|
+
factory_ = obj_.factory
|
144
|
+
if @tag_format == :wkt11_strict
|
145
|
+
@cur_support_z = nil
|
146
|
+
@cur_support_m = nil
|
147
|
+
else
|
148
|
+
@cur_support_z = factory_.property(:has_z_coordinate)
|
149
|
+
@cur_support_m = factory_.property(:has_m_coordinate)
|
150
|
+
end
|
151
|
+
str_ = _generate_feature(obj_, true)
|
152
|
+
if @convert_case == :upper
|
153
|
+
str_.upcase
|
154
|
+
elsif @convert_case == :lower
|
155
|
+
str_.downcase
|
156
|
+
else
|
157
|
+
str_
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
def _generate_feature(obj_, toplevel_=false) # :nodoc:
|
163
|
+
type_ = obj_.geometry_type
|
164
|
+
tag_ = type_.type_name
|
165
|
+
if @tag_format == :ewkt
|
166
|
+
if @cur_support_m && !@cur_support_z
|
167
|
+
tag_ << 'M'
|
168
|
+
end
|
169
|
+
if toplevel_ && @emit_ewkt_srid
|
170
|
+
tag_ = "SRID=#{obj_.srid};#{tag_}"
|
171
|
+
end
|
172
|
+
elsif @tag_format == :wkt12
|
173
|
+
if @cur_support_z
|
174
|
+
if @cur_support_m
|
175
|
+
tag_ << ' ZM'
|
176
|
+
else
|
177
|
+
tag_ << ' Z'
|
178
|
+
end
|
179
|
+
elsif @cur_support_m
|
180
|
+
tag_ << ' M'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
if type_ == Feature::Point
|
184
|
+
tag_ + _generate_point(obj_)
|
185
|
+
elsif type_.subtype_of?(Feature::LineString)
|
186
|
+
tag_ + _generate_line_string(obj_)
|
187
|
+
elsif type_ == Feature::Polygon
|
188
|
+
tag_ + _generate_polygon(obj_)
|
189
|
+
elsif type_ == Feature::GeometryCollection
|
190
|
+
tag_ + _generate_geometry_collection(obj_)
|
191
|
+
elsif type_ == Feature::MultiPoint
|
192
|
+
tag_ + _generate_multi_point(obj_)
|
193
|
+
elsif type_ == Feature::MultiLineString
|
194
|
+
tag_ + _generate_multi_line_string(obj_)
|
195
|
+
elsif type_ == Feature::MultiPolygon
|
196
|
+
tag_ + _generate_multi_polygon(obj_)
|
197
|
+
else
|
198
|
+
raise Error::ParseError, "Unrecognized geometry type: #{type_}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
def _generate_coords(obj_) # :nodoc:
|
204
|
+
str_ = "#{obj_.x.to_s} #{obj_.y.to_s}"
|
205
|
+
str_ << " #{obj_.z.to_s}" if @cur_support_z
|
206
|
+
str_ << " #{obj_.m.to_s}" if @cur_support_m
|
207
|
+
str_
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
def _generate_point(obj_) # :nodoc:
|
212
|
+
"#{@begin_bracket}#{_generate_coords(obj_)}#{@end_bracket}"
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
def _generate_line_string(obj_, contained_=false) # :nodoc:
|
217
|
+
if obj_.is_empty?
|
218
|
+
contained_ ? 'EMPTY' : ' EMPTY'
|
219
|
+
else
|
220
|
+
"#{@begin_bracket}#{obj_.points.map{ |p_| _generate_coords(p_) }.join(',')}#{@end_bracket}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
def _generate_polygon(obj_, contained_=false) # :nodoc:
|
226
|
+
if obj_.is_empty?
|
227
|
+
contained_ ? 'EMPTY' : ' EMPTY'
|
228
|
+
else
|
229
|
+
"#{@begin_bracket}#{([_generate_line_string(obj_.exterior_ring, true)] + obj_.interior_rings.map{ |r_| _generate_line_string(r_, true) }).join(',')}#{@end_bracket}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
def _generate_geometry_collection(obj_) # :nodoc:
|
235
|
+
if obj_.is_empty?
|
236
|
+
' EMPTY'
|
237
|
+
else
|
238
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_feature(f_) }.join(',')}#{@end_bracket}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
def _generate_multi_point(obj_) # :nodoc:
|
244
|
+
if obj_.is_empty?
|
245
|
+
" EMPTY"
|
246
|
+
else
|
247
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_point(f_) }.join(',')}#{@end_bracket}"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
def _generate_multi_line_string(obj_) # :nodoc:
|
253
|
+
if obj_.is_empty?
|
254
|
+
" EMPTY"
|
255
|
+
else
|
256
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_line_string(f_, true) }.join(',')}#{@end_bracket}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
def _generate_multi_polygon(obj_) # :nodoc:
|
262
|
+
if obj_.is_empty?
|
263
|
+
" EMPTY"
|
264
|
+
else
|
265
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_polygon(f_, true) }.join(',')}#{@end_bracket}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|