rgeo 0.1.14 → 0.1.15
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 +6 -0
- data/Version +1 -1
- data/lib/rgeo.rb +80 -30
- data/lib/rgeo/all.rb +48 -0
- data/lib/rgeo/cartesian.rb +37 -12
- data/lib/rgeo/cartesian/calculations.rb +5 -0
- data/lib/rgeo/cartesian/{simple_factory.rb → factory.rb} +14 -17
- data/lib/rgeo/cartesian/{simple_feature_classes.rb → feature_classes.rb} +55 -55
- data/lib/rgeo/cartesian/{simple_feature_methods.rb → feature_methods.rb} +7 -3
- data/lib/rgeo/cartesian/interface.rb +7 -3
- data/lib/rgeo/errors.rb +4 -0
- data/lib/rgeo/features.rb +25 -20
- data/lib/rgeo/geo_json.rb +10 -8
- data/lib/rgeo/geography.rb +10 -16
- data/lib/rgeo/geography/all.rb +40 -0
- data/lib/rgeo/geography/factory.rb +2 -2
- data/lib/rgeo/geography/{factories.rb → interface.rb} +4 -2
- data/lib/rgeo/geography/simple_mercator.rb +69 -0
- data/lib/rgeo/geography/simple_mercator/feature_classes.rb +62 -62
- data/lib/rgeo/geography/simple_mercator/projector.rb +1 -1
- data/lib/rgeo/geography/simple_spherical.rb +68 -0
- data/lib/rgeo/geography/simple_spherical/calculations.rb +2 -2
- data/lib/rgeo/geography/simple_spherical/feature_classes.rb +44 -44
- data/lib/rgeo/geos.rb +12 -9
- data/lib/rgeo/impl_helpers.rb +14 -9
- data/lib/rgeo/impl_helpers/basic_geometry_collection_methods.rb +10 -0
- data/lib/rgeo/impl_helpers/basic_point_methods.rb +3 -0
- data/lib/rgeo/{geography/helper.rb → impl_helpers/math.rb} +3 -3
- data/lib/rgeo/wkrep.rb +32 -12
- data/lib/rgeo/wkrep/wkb_generator.rb +95 -9
- data/lib/rgeo/wkrep/wkb_parser.rb +117 -9
- data/lib/rgeo/wkrep/wkt_generator.rb +106 -18
- data/lib/rgeo/wkrep/wkt_parser.rb +203 -59
- data/tests/simple_cartesian/tc_calculations.rb +8 -8
- data/tests/wkrep/tc_wkt_generator.rb +362 -0
- data/tests/wkrep/tc_wkt_parser.rb +490 -0
- metadata +16 -8
@@ -39,24 +39,132 @@ module RGeo
|
|
39
39
|
module WKRep
|
40
40
|
|
41
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
|
+
# The following options are recognized. These can be passed to the
|
53
|
+
# constructor, or set on the object afterwards.
|
54
|
+
#
|
55
|
+
# <tt>:default_factory</tt>::
|
56
|
+
# The default factory for generated geometries, used when no SRID
|
57
|
+
# is explicitly specified in the input. If none is provided, the
|
58
|
+
# default cartesian factory will be used.
|
59
|
+
# <tt>:factory_from_srid</tt>::
|
60
|
+
# A Proc that takes an SRID as the sole argument, and returns a
|
61
|
+
# factory for generated geometries when that SRID is specified in
|
62
|
+
# the input. If no such Proc is provided, the default_factory is
|
63
|
+
# used, regardless of the input SRID.
|
64
|
+
# <tt>:support_ewkb</tt>::
|
65
|
+
# Activate support for PostGIS EWKB type codes, which use high
|
66
|
+
# order bits in the type code to signal the presence of Z, M, and
|
67
|
+
# SRID values in the data. Default is false.
|
68
|
+
# <tt>:support_wkb12</tt>::
|
69
|
+
# Activate support for SFS 1.2 extensions to the type codes, which
|
70
|
+
# use values greater than 1000 to signal the presence of Z and M
|
71
|
+
# values in the data. SFS 1.2 types such as triangle, tin, and
|
72
|
+
# polyhedralsurface are NOT yet supported. Default is false.
|
73
|
+
# <tt>:ignore_extra_bytes</tt>::
|
74
|
+
# If true, extra bytes at the end of the data are ignored. If
|
75
|
+
# false (the default), extra bytes will trigger a parse error.
|
76
|
+
|
42
77
|
class WKBParser
|
43
78
|
|
44
79
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@
|
50
|
-
@
|
80
|
+
# Create and configure a WKB parser. See the WKBParser
|
81
|
+
# documentation for the options that can be passed.
|
82
|
+
|
83
|
+
def initialize(opts_={})
|
84
|
+
@default_factory = opts_[:default_factory] || Cartesian.preferred_factory
|
85
|
+
@factory_from_srid = opts_[:factory_from_srid]
|
86
|
+
@support_ewkb = opts_[:support_ewkb] ? true : false
|
87
|
+
@support_wkb12 = opts_[:support_wkb12] ? true : false
|
88
|
+
@ignore_extra_bytes = opts_[:ignore_extra_bytes] ? true : false
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Returns the default factory. See WKBParser for details.
|
93
|
+
def default_factory
|
94
|
+
@default_factory
|
95
|
+
end
|
96
|
+
|
97
|
+
# Sets the default factory. See WKBParser for details.
|
98
|
+
def default_factory=(value_)
|
99
|
+
@default_factory = value_ || Cartesian.preferred_factory
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns true if this parser has a factory_from_srid procedure.
|
103
|
+
# See WKBParser for details.
|
104
|
+
def has_factory_from_srid?
|
105
|
+
@factory_from_srid ? true : false
|
106
|
+
end
|
107
|
+
|
108
|
+
# Sets the factory_from_srid. See WKBParser for details.
|
109
|
+
def factory_from_srid=(value_)
|
110
|
+
@factory_from_srid = value_
|
111
|
+
end
|
112
|
+
|
113
|
+
# Sets the factory_from_srid to the given block.
|
114
|
+
# See WKBParser for details.
|
115
|
+
def set_factory_from_srid(&block_)
|
116
|
+
@factory_from_srid = block_
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns true if this parser supports EWKB.
|
120
|
+
# See WKBParser for details.
|
121
|
+
def support_ewkb?
|
122
|
+
@support_ewkb
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sets the the support_ewkb flag. See WKBParser for details.
|
126
|
+
def support_ewkb=(value_)
|
127
|
+
@support_ewkb = value_ ? true : false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns true if this parser supports SFS 1.2 extensions.
|
131
|
+
# See WKBParser for details.
|
132
|
+
def support_wkb12?
|
133
|
+
@support_wkb12
|
134
|
+
end
|
135
|
+
|
136
|
+
# Sets the the support_wkb12 flag. See WKBParser for details.
|
137
|
+
def support_wkb12=(value_)
|
138
|
+
@support_wkb12 = value_ ? true : false
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns true if this parser ignores extra bytes.
|
142
|
+
# See WKBParser for details.
|
143
|
+
def ignore_extra_bytes?
|
144
|
+
@ignore_extra_bytes
|
51
145
|
end
|
52
146
|
|
147
|
+
# Sets the the ignore_extra_bytes flag. See WKBParser for details.
|
148
|
+
def ignore_extra_bytes=(value_)
|
149
|
+
@ignore_extra_bytes = value_ ? true : false
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Parse the given hex string, and return a geometry object.
|
154
|
+
|
155
|
+
def parse_hex(str_)
|
156
|
+
parse([str_].pack('H*'))
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# Parse the given binary data, and return a geometry object.
|
53
161
|
|
54
162
|
def parse(data_)
|
55
163
|
@cur_has_z = nil
|
56
164
|
@cur_has_m = nil
|
57
165
|
@cur_srid = nil
|
58
166
|
@cur_dims = 2
|
59
|
-
@cur_factory = @
|
167
|
+
@cur_factory = @default_factory
|
60
168
|
begin
|
61
169
|
_start_scanner(data_)
|
62
170
|
obj_ = _parse_object(false)
|
@@ -108,8 +216,8 @@ module RGeo
|
|
108
216
|
@cur_has_m = has_m_
|
109
217
|
@cur_dims = 2 + (@cur_has_z ? 1 : 0) + (@cur_has_m ? 1 : 0)
|
110
218
|
@cur_srid = srid_
|
111
|
-
if srid_ && @
|
112
|
-
@cur_factory = @
|
219
|
+
if srid_ && @factory_from_srid
|
220
|
+
@cur_factory = @factory_from_srid.call(srid_)
|
113
221
|
end
|
114
222
|
if @cur_has_z && !@cur_factory.has_capability?(:z_coordinate)
|
115
223
|
raise Errors::ParseError, "Data has Z coordinates but the factory doesn't have z_coordinate capability"
|
@@ -39,19 +39,107 @@ module RGeo
|
|
39
39
|
module WKRep
|
40
40
|
|
41
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
|
+
|
42
79
|
class WKTGenerator
|
43
80
|
|
44
81
|
|
82
|
+
# Create and configure a WKT generator. See the WKTGenerator
|
83
|
+
# documentation for the options that can be passed.
|
84
|
+
|
45
85
|
def initialize(opts_={})
|
46
|
-
@tag_format = opts_[:tag_format]
|
47
|
-
@emit_ewkt_srid = opts_[:emit_ewkt_srid] if @tag_format == :ewkt
|
48
|
-
@
|
49
|
-
@
|
50
|
-
@case = opts_[:case]
|
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]
|
51
90
|
end
|
52
91
|
|
53
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
|
+
|
54
140
|
def generate(obj_)
|
141
|
+
@begin_bracket = @square_brackets ? '[' : '('
|
142
|
+
@end_bracket = @square_brackets ? ']' : ')'
|
55
143
|
factory_ = obj_.factory
|
56
144
|
if @tag_format == :wkt11_strict
|
57
145
|
@cur_support_z = nil
|
@@ -61,9 +149,9 @@ module RGeo
|
|
61
149
|
@cur_support_m = factory_.has_capability?(:m_coordinate)
|
62
150
|
end
|
63
151
|
str_ = _generate_feature(obj_, true)
|
64
|
-
if @
|
152
|
+
if @convert_case == :upper
|
65
153
|
str_.upcase
|
66
|
-
elsif @
|
154
|
+
elsif @convert_case == :lower
|
67
155
|
str_.downcase
|
68
156
|
else
|
69
157
|
str_
|
@@ -78,6 +166,9 @@ module RGeo
|
|
78
166
|
if @cur_support_m && !@cur_support_z
|
79
167
|
tag_ << 'M'
|
80
168
|
end
|
169
|
+
if toplevel_ && @emit_ewkt_srid
|
170
|
+
tag_ = "SRID=#{obj_.srid};#{tag_}"
|
171
|
+
end
|
81
172
|
elsif @tag_format == :wkt12
|
82
173
|
if @cur_support_z
|
83
174
|
if @cur_support_m
|
@@ -89,9 +180,6 @@ module RGeo
|
|
89
180
|
tag_ << ' M'
|
90
181
|
end
|
91
182
|
end
|
92
|
-
if toplevel_ && @emit_ewkt_srid
|
93
|
-
tag_ = "SRID=#{obj_.srid};#{tag_}"
|
94
|
-
end
|
95
183
|
if type_ == Features::Point
|
96
184
|
tag_ + _generate_point(obj_)
|
97
185
|
elsif type_.subtype_of?(Features::LineString)
|
@@ -125,27 +213,27 @@ module RGeo
|
|
125
213
|
end
|
126
214
|
|
127
215
|
|
128
|
-
def _generate_line_string(obj_) # :nodoc:
|
216
|
+
def _generate_line_string(obj_, contained_=false) # :nodoc:
|
129
217
|
if obj_.is_empty?
|
130
|
-
|
218
|
+
contained_ ? 'EMPTY' : ' EMPTY'
|
131
219
|
else
|
132
220
|
"#{@begin_bracket}#{obj_.points.map{ |p_| _generate_coords(p_) }.join(',')}#{@end_bracket}"
|
133
221
|
end
|
134
222
|
end
|
135
223
|
|
136
224
|
|
137
|
-
def _generate_polygon(obj_) # :nodoc:
|
225
|
+
def _generate_polygon(obj_, contained_=false) # :nodoc:
|
138
226
|
if obj_.is_empty?
|
139
|
-
|
227
|
+
contained_ ? 'EMPTY' : ' EMPTY'
|
140
228
|
else
|
141
|
-
"#{@begin_bracket}#{([_generate_line_string(obj_.exterior_ring)] + obj_.interior_rings.map{ |r_| _generate_line_string(r_) }).join(',')}#{@end_bracket}"
|
229
|
+
"#{@begin_bracket}#{([_generate_line_string(obj_.exterior_ring, true)] + obj_.interior_rings.map{ |r_| _generate_line_string(r_, true) }).join(',')}#{@end_bracket}"
|
142
230
|
end
|
143
231
|
end
|
144
232
|
|
145
233
|
|
146
234
|
def _generate_geometry_collection(obj_) # :nodoc:
|
147
235
|
if obj_.is_empty?
|
148
|
-
|
236
|
+
' EMPTY'
|
149
237
|
else
|
150
238
|
"#{@begin_bracket}#{obj_.map{ |f_| _generate_feature(f_) }.join(',')}#{@end_bracket}"
|
151
239
|
end
|
@@ -165,7 +253,7 @@ module RGeo
|
|
165
253
|
if obj_.is_empty?
|
166
254
|
" EMPTY"
|
167
255
|
else
|
168
|
-
"#{@begin_bracket}#{obj_.map{ |f_| _generate_line_string(f_) }.join(',')}#{@end_bracket}"
|
256
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_line_string(f_, true) }.join(',')}#{@end_bracket}"
|
169
257
|
end
|
170
258
|
end
|
171
259
|
|
@@ -174,7 +262,7 @@ module RGeo
|
|
174
262
|
if obj_.is_empty?
|
175
263
|
" EMPTY"
|
176
264
|
else
|
177
|
-
"#{@begin_bracket}#{obj_.map{ |f_| _generate_polygon(f_) }.join(',')}#{@end_bracket}"
|
265
|
+
"#{@begin_bracket}#{obj_.map{ |f_| _generate_polygon(f_, true) }.join(',')}#{@end_bracket}"
|
178
266
|
end
|
179
267
|
end
|
180
268
|
|
@@ -42,42 +42,164 @@ module RGeo
|
|
42
42
|
module WKRep
|
43
43
|
|
44
44
|
|
45
|
+
# This class provides the functionality of parsing a geometry from
|
46
|
+
# WKT (well-known text) format. You may also customize the parser
|
47
|
+
# to recognize PostGIS EWKT extensions to the input, or Simple
|
48
|
+
# Features Specification 1.2 extensions for Z and M coordinates.
|
49
|
+
#
|
50
|
+
# To use this class, create an instance with the desired settings and
|
51
|
+
# customizations, and call the parse method.
|
52
|
+
#
|
53
|
+
# === Configuration options
|
54
|
+
#
|
55
|
+
# The following options are recognized. These can be passed to the
|
56
|
+
# constructor, or set on the object afterwards.
|
57
|
+
#
|
58
|
+
# <tt>:default_factory</tt>::
|
59
|
+
# The default factory for generated geometries, used when no SRID
|
60
|
+
# is explicitly specified in the input. If none is provided, the
|
61
|
+
# default cartesian factory will be used.
|
62
|
+
# <tt>:factory_from_srid</tt>::
|
63
|
+
# A Proc that takes an SRID as the sole argument, and returns a
|
64
|
+
# factory for generated geometries when that SRID is specified in
|
65
|
+
# the input. If no such Proc is provided, the default_factory is
|
66
|
+
# used, regardless of the input SRID.
|
67
|
+
# <tt>:support_ewkt</tt>::
|
68
|
+
# Activate support for PostGIS EWKT type tags, which appends an "M"
|
69
|
+
# to tags to indicate the presence of M but not Z, and also
|
70
|
+
# recognizes the SRID prefix. Default is false.
|
71
|
+
# <tt>:support_wkt12</tt>::
|
72
|
+
# Activate support for SFS 1.2 extensions to the type codes, which
|
73
|
+
# use a "M", "Z", or "ZM" token to signal the presence of Z and M
|
74
|
+
# values in the data. SFS 1.2 types such as triangle, tin, and
|
75
|
+
# polyhedralsurface are NOT yet supported. Default is false.
|
76
|
+
# <tt>:strict_wkt11</tt>::
|
77
|
+
# If true, parsing will proceed in SFS 1.1 strict mode, which
|
78
|
+
# disallows any values other than X or Y. This has no effect if
|
79
|
+
# support_ewkt or support_wkt12 are active. Default is false.
|
80
|
+
# <tt>:ignore_extra_tokens</tt>::
|
81
|
+
# If true, extra tokens at the end of the data are ignored. If
|
82
|
+
# false (the default), extra tokens will trigger a parse error.
|
83
|
+
|
45
84
|
class WKTParser
|
46
85
|
|
47
86
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
87
|
+
# Create and configure a WKT parser. See the WKTParser
|
88
|
+
# documentation for the options that can be passed.
|
89
|
+
|
90
|
+
def initialize(opts_={})
|
91
|
+
@default_factory = opts_[:default_factory] || Cartesian.preferred_factory
|
92
|
+
@factory_from_srid = opts_[:factory_from_srid]
|
93
|
+
@support_ewkt = opts_[:support_ewkt] ? true : false
|
94
|
+
@support_wkt12 = opts_[:support_wkt12] ? true : false
|
95
|
+
@strict_wkt11 = @support_ewkt || @support_wkt12 ? false : opts_[:strict_wkt11] ? true : false
|
96
|
+
@ignore_extra_tokens = opts_[:ignore_extra_tokens] ? true : false
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Returns the default factory. See WKTParser for details.
|
101
|
+
def default_factory
|
102
|
+
@default_factory
|
103
|
+
end
|
104
|
+
|
105
|
+
# Sets the default factory. See WKTParser for details.
|
106
|
+
def default_factory=(value_)
|
107
|
+
@default_factory = value_ || Cartesian.preferred_factory
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns true if this parser has a factory_from_srid procedure.
|
111
|
+
# See WKTParser for details.
|
112
|
+
def has_factory_from_srid?
|
113
|
+
@factory_from_srid ? true : false
|
114
|
+
end
|
115
|
+
|
116
|
+
# Sets the factory_from_srid. See WKTParser for details.
|
117
|
+
def factory_from_srid=(value_)
|
118
|
+
@factory_from_srid = value_
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sets the factory_from_srid to the given block.
|
122
|
+
# See WKTParser for details.
|
123
|
+
def set_factory_from_srid(&block_)
|
124
|
+
@factory_from_srid = block_
|
125
|
+
end
|
126
|
+
|
127
|
+
# Returns true if this parser supports EWKT.
|
128
|
+
# See WKTParser for details.
|
129
|
+
def support_ewkt?
|
130
|
+
@support_ewkt
|
55
131
|
end
|
56
132
|
|
133
|
+
# Sets the the support_ewkt flag. See WKTParser for details.
|
134
|
+
def support_ewkt=(value_)
|
135
|
+
@support_ewkt = value_ ? true : false
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns true if this parser supports SFS 1.2 extensions.
|
139
|
+
# See WKTParser for details.
|
140
|
+
def support_wkt12?
|
141
|
+
@support_wkt12
|
142
|
+
end
|
143
|
+
|
144
|
+
# Sets the the support_wkt12 flag. See WKTParser for details.
|
145
|
+
def support_wkt12=(value_)
|
146
|
+
@support_wkt12 = value_ ? true : false
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns true if this parser strictly adheres to WKT 1.1.
|
150
|
+
# See WKTParser for details.
|
151
|
+
def strict_wkt11?
|
152
|
+
@strict_wkt11
|
153
|
+
end
|
154
|
+
|
155
|
+
# Sets the the strict_wkt11 flag. See WKTParser for details.
|
156
|
+
def strict_wkt11=(value_)
|
157
|
+
@strict_wkt11 = value_ ? true : false
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns true if this parser ignores extra tokens.
|
161
|
+
# See WKTParser for details.
|
162
|
+
def ignore_extra_tokens?
|
163
|
+
@ignore_extra_tokens
|
164
|
+
end
|
165
|
+
|
166
|
+
# Sets the the ignore_extra_tokens flag. See WKTParser for details.
|
167
|
+
def ignore_extra_tokens=(value_)
|
168
|
+
@ignore_extra_tokens = value_ ? true : false
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
# Parse the given string, and return a geometry object.
|
57
173
|
|
58
174
|
def parse(str_)
|
59
|
-
@cur_factory = @
|
175
|
+
@cur_factory = @default_factory
|
60
176
|
str_ = str_.downcase
|
61
|
-
if @support_ewkt && str_ =~ /^srid=(\d+);/
|
177
|
+
if @support_ewkt && str_ =~ /^srid=(\d+);/i
|
62
178
|
str_ = $'
|
63
|
-
if @
|
64
|
-
@cur_factory = @
|
179
|
+
if @factory_from_srid
|
180
|
+
@cur_factory = @factory_from_srid.call($1.to_i)
|
65
181
|
end
|
66
182
|
end
|
67
183
|
@cur_factory_support_z = @cur_factory.has_capability?(:z_coordinate)
|
68
184
|
@cur_factory_support_m = @cur_factory.has_capability?(:m_coordinate)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
185
|
+
@cur_expect_z = nil
|
186
|
+
@cur_expect_m = nil
|
187
|
+
begin
|
188
|
+
_start_scanner(str_)
|
189
|
+
obj_ = _parse_type_tag
|
190
|
+
if @cur_token && !@ignore_extra_tokens
|
191
|
+
raise Errors::ParseError, "Extra tokens beginning with #{@cur_token.inspect}."
|
192
|
+
end
|
193
|
+
ensure
|
194
|
+
_clean_scanner
|
73
195
|
end
|
74
196
|
obj_
|
75
197
|
end
|
76
198
|
|
77
199
|
|
78
|
-
def _parse_type_tag
|
200
|
+
def _parse_type_tag # :nodoc:
|
79
201
|
_expect_token_type(::String)
|
80
|
-
if @
|
202
|
+
if @support_ewkt && @cur_token =~ /^(.+)(m)$/
|
81
203
|
type_ = $1
|
82
204
|
zm_ = $2
|
83
205
|
else
|
@@ -89,46 +211,46 @@ module RGeo
|
|
89
211
|
zm_ = @cur_token
|
90
212
|
_next_token
|
91
213
|
end
|
92
|
-
if zm_.length > 0 ||
|
93
|
-
|
94
|
-
if
|
214
|
+
if zm_.length > 0 || @strict_wkt11
|
215
|
+
expect_z_ = zm_[0,1] == 'z'
|
216
|
+
if !@cur_expect_z.nil? && expect_z_ != @cur_expect_z
|
95
217
|
raise Errors::ParseError, "Surrounding collection has Z but contained geometry doesn't."
|
96
218
|
end
|
97
|
-
|
98
|
-
|
99
|
-
if
|
219
|
+
@cur_expect_z = expect_z_
|
220
|
+
expect_m_ = zm_[-1,1] == 'm'
|
221
|
+
if !@cur_expect_m.nil? && expect_m_ != @cur_expect_m
|
100
222
|
raise Errors::ParseError, "Surrounding collection has M but contained geometry doesn't."
|
101
223
|
end
|
102
|
-
|
224
|
+
@cur_expect_m = expect_m_
|
103
225
|
end
|
104
|
-
if
|
226
|
+
if @cur_expect_z && !@cur_factory_support_z
|
105
227
|
raise Errors::ParseError, "Type tag declares #{zm_.inspect} but factory doesn't support Z."
|
106
228
|
end
|
107
|
-
if
|
229
|
+
if @cur_expect_m && !@cur_factory_support_m
|
108
230
|
raise Errors::ParseError, "Type tag declares #{zm_.inspect} but factory doesn't support M."
|
109
231
|
end
|
110
232
|
case type_
|
111
233
|
when 'point'
|
112
|
-
_parse_point(
|
234
|
+
_parse_point(true)
|
113
235
|
when 'linestring'
|
114
|
-
_parse_line_string
|
236
|
+
_parse_line_string
|
115
237
|
when 'polygon'
|
116
|
-
_parse_polygon
|
238
|
+
_parse_polygon
|
117
239
|
when 'geometrycollection'
|
118
|
-
_parse_geometry_collection
|
240
|
+
_parse_geometry_collection
|
119
241
|
when 'multipoint'
|
120
|
-
_parse_multi_point
|
242
|
+
_parse_multi_point
|
121
243
|
when 'multilinestring'
|
122
|
-
_parse_multi_line_string
|
244
|
+
_parse_multi_line_string
|
123
245
|
when 'multipolygon'
|
124
|
-
_parse_multi_polygon
|
246
|
+
_parse_multi_polygon
|
125
247
|
else
|
126
|
-
raise Errors::ParseError, "Unknown type tag: #{
|
248
|
+
raise Errors::ParseError, "Unknown type tag: #{type_.inspect}."
|
127
249
|
end
|
128
250
|
end
|
129
251
|
|
130
252
|
|
131
|
-
def _parse_coords
|
253
|
+
def _parse_coords # :nodoc:
|
132
254
|
_expect_token_type(::Numeric)
|
133
255
|
x_ = @cur_token
|
134
256
|
_next_token
|
@@ -136,34 +258,50 @@ module RGeo
|
|
136
258
|
y_ = @cur_token
|
137
259
|
_next_token
|
138
260
|
extra_ = []
|
139
|
-
if
|
261
|
+
if @cur_expect_z.nil?
|
140
262
|
while ::Numeric === @cur_token
|
141
263
|
extra_ << @cur_token
|
142
264
|
_next_token
|
143
265
|
end
|
266
|
+
num_extras_ = extra_.size
|
267
|
+
@cur_expect_z = num_extras_ > 0 && @cur_factory_support_z ? true : false
|
268
|
+
num_extras_ -= 1 if @cur_expect_z
|
269
|
+
@cur_expect_m = num_extras_ > 0 && @cur_factory_support_m ? true : false
|
270
|
+
num_extras_ -= 1 if @cur_expect_m
|
271
|
+
if num_extras_ > 0
|
272
|
+
raise Errors::ParseError, "Found #{extra_.size+2} coordinates, which is too many for this factory."
|
273
|
+
end
|
144
274
|
else
|
145
|
-
if
|
146
|
-
|
147
|
-
|
148
|
-
|
275
|
+
if @cur_factory_support_z
|
276
|
+
if @cur_expect_z
|
277
|
+
_expect_token_type(::Numeric)
|
278
|
+
extra_ << @cur_token
|
279
|
+
_next_token
|
280
|
+
else
|
281
|
+
extra_ << 0
|
282
|
+
end
|
149
283
|
end
|
150
|
-
if
|
151
|
-
|
152
|
-
|
153
|
-
|
284
|
+
if @cur_factory_support_m
|
285
|
+
if @cur_expect_m
|
286
|
+
_expect_token_type(::Numeric)
|
287
|
+
extra_ << @cur_token
|
288
|
+
_next_token
|
289
|
+
else
|
290
|
+
extra_ << 0
|
291
|
+
end
|
154
292
|
end
|
155
293
|
end
|
156
294
|
@cur_factory.point(x_, y_, *extra_)
|
157
295
|
end
|
158
296
|
|
159
297
|
|
160
|
-
def _parse_point(
|
298
|
+
def _parse_point(convert_empty_=false) # :nodoc:
|
161
299
|
if convert_empty_ && @cur_token == 'empty'
|
162
300
|
point_ = @cur_factory.multi_point([])
|
163
301
|
else
|
164
302
|
_expect_token_type(:begin)
|
165
303
|
_next_token
|
166
|
-
point_ = _parse_coords
|
304
|
+
point_ = _parse_coords
|
167
305
|
_expect_token_type(:end)
|
168
306
|
end
|
169
307
|
_next_token
|
@@ -171,13 +309,13 @@ module RGeo
|
|
171
309
|
end
|
172
310
|
|
173
311
|
|
174
|
-
def _parse_line_string
|
312
|
+
def _parse_line_string # :nodoc:
|
175
313
|
points_ = []
|
176
314
|
if @cur_token != 'empty'
|
177
315
|
_expect_token_type(:begin)
|
178
316
|
_next_token
|
179
317
|
loop do
|
180
|
-
points_ << _parse_coords
|
318
|
+
points_ << _parse_coords
|
181
319
|
break if @cur_token == :end
|
182
320
|
_expect_token_type(:comma)
|
183
321
|
_next_token
|
@@ -188,19 +326,19 @@ module RGeo
|
|
188
326
|
end
|
189
327
|
|
190
328
|
|
191
|
-
def _parse_polygon
|
329
|
+
def _parse_polygon # :nodoc:
|
192
330
|
inner_rings_ = []
|
193
331
|
if @cur_token == 'empty'
|
194
332
|
outer_ring_ = @cur_factory.linear_ring([])
|
195
333
|
else
|
196
334
|
_expect_token_type(:begin)
|
197
335
|
_next_token
|
198
|
-
outer_ring_ = _parse_line_string
|
336
|
+
outer_ring_ = _parse_line_string
|
199
337
|
loop do
|
200
338
|
break if @cur_token == :end
|
201
339
|
_expect_token_type(:comma)
|
202
340
|
_next_token
|
203
|
-
inner_rings_ << _parse_line_string
|
341
|
+
inner_rings_ << _parse_line_string
|
204
342
|
end
|
205
343
|
end
|
206
344
|
_next_token
|
@@ -208,13 +346,13 @@ module RGeo
|
|
208
346
|
end
|
209
347
|
|
210
348
|
|
211
|
-
def _parse_geometry_collection
|
349
|
+
def _parse_geometry_collection # :nodoc:
|
212
350
|
geometries_ = []
|
213
351
|
if @cur_token != 'empty'
|
214
352
|
_expect_token_type(:begin)
|
215
353
|
_next_token
|
216
354
|
loop do
|
217
|
-
geometries_ << _parse_type_tag
|
355
|
+
geometries_ << _parse_type_tag
|
218
356
|
break if @cur_token == :end
|
219
357
|
_expect_token_type(:comma)
|
220
358
|
_next_token
|
@@ -225,13 +363,13 @@ module RGeo
|
|
225
363
|
end
|
226
364
|
|
227
365
|
|
228
|
-
def _parse_multi_point
|
366
|
+
def _parse_multi_point # :nodoc:
|
229
367
|
points_ = []
|
230
368
|
if @cur_token != 'empty'
|
231
369
|
_expect_token_type(:begin)
|
232
370
|
_next_token
|
233
371
|
loop do
|
234
|
-
points_ << _parse_point
|
372
|
+
points_ << _parse_point
|
235
373
|
break if @cur_token == :end
|
236
374
|
_expect_token_type(:comma)
|
237
375
|
_next_token
|
@@ -242,13 +380,13 @@ module RGeo
|
|
242
380
|
end
|
243
381
|
|
244
382
|
|
245
|
-
def _parse_multi_line_string
|
383
|
+
def _parse_multi_line_string # :nodoc:
|
246
384
|
line_strings_ = []
|
247
385
|
if @cur_token != 'empty'
|
248
386
|
_expect_token_type(:begin)
|
249
387
|
_next_token
|
250
388
|
loop do
|
251
|
-
line_strings_ << _parse_line_string
|
389
|
+
line_strings_ << _parse_line_string
|
252
390
|
break if @cur_token == :end
|
253
391
|
_expect_token_type(:comma)
|
254
392
|
_next_token
|
@@ -259,13 +397,13 @@ module RGeo
|
|
259
397
|
end
|
260
398
|
|
261
399
|
|
262
|
-
def _parse_multi_polygon
|
400
|
+
def _parse_multi_polygon # :nodoc:
|
263
401
|
polygons_ = []
|
264
402
|
if @cur_token != 'empty'
|
265
403
|
_expect_token_type(:begin)
|
266
404
|
_next_token
|
267
405
|
loop do
|
268
|
-
polygons_ << _parse_polygon
|
406
|
+
polygons_ << _parse_polygon
|
269
407
|
break if @cur_token == :end
|
270
408
|
_expect_token_type(:comma)
|
271
409
|
_next_token
|
@@ -282,6 +420,12 @@ module RGeo
|
|
282
420
|
end
|
283
421
|
|
284
422
|
|
423
|
+
def _clean_scanner # :nodoc:
|
424
|
+
@_scanner = nil
|
425
|
+
@cur_token = nil
|
426
|
+
end
|
427
|
+
|
428
|
+
|
285
429
|
def _expect_token_type(type_) # :nodoc:
|
286
430
|
unless type_ === @cur_token
|
287
431
|
raise Errors::ParseError, "#{type_.inspect} expected but #{@cur_token.inspect} found."
|