rgeo 0.1.13 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/History.rdoc +11 -0
  2. data/Version +1 -1
  3. data/ext/geos_c_impl/factory.c +35 -40
  4. data/ext/geos_c_impl/factory.h +4 -1
  5. data/ext/geos_c_impl/geometry_collection.c +5 -5
  6. data/ext/geos_c_impl/geometry_collection.h +1 -1
  7. data/ext/geos_c_impl/line_string.c +129 -116
  8. data/ext/geos_c_impl/point.c +22 -33
  9. data/ext/geos_c_impl/point.h +1 -6
  10. data/ext/geos_c_impl/polygon.c +4 -4
  11. data/ext/geos_c_impl/polygon.h +1 -1
  12. data/lib/rgeo.rb +1 -0
  13. data/lib/rgeo/cartesian/simple_factory.rb +20 -4
  14. data/lib/rgeo/errors.rb +8 -0
  15. data/lib/rgeo/features/factory.rb +35 -1
  16. data/lib/rgeo/features/point.rb +22 -0
  17. data/lib/rgeo/features/polygon.rb +1 -2
  18. data/lib/rgeo/features/types.rb +70 -16
  19. data/lib/rgeo/geography/factories.rb +40 -3
  20. data/lib/rgeo/geography/factory.rb +25 -5
  21. data/lib/rgeo/geography/simple_mercator/feature_methods.rb +2 -6
  22. data/lib/rgeo/geography/simple_mercator/projector.rb +1 -1
  23. data/lib/rgeo/geos/factory.rb +40 -46
  24. data/lib/rgeo/geos/interface.rb +10 -0
  25. data/lib/rgeo/impl_helpers.rb +0 -1
  26. data/lib/rgeo/impl_helpers/basic_geometry_methods.rb +2 -2
  27. data/lib/rgeo/impl_helpers/basic_point_methods.rb +12 -14
  28. data/lib/rgeo/wkrep.rb +59 -0
  29. data/lib/rgeo/wkrep/wkb_generator.rb +181 -0
  30. data/lib/rgeo/wkrep/wkb_parser.rb +205 -0
  31. data/lib/rgeo/wkrep/wkt_generator.rb +187 -0
  32. data/lib/rgeo/wkrep/wkt_parser.rb +321 -0
  33. data/tests/common/line_string_tests.rb +26 -2
  34. data/tests/common/point_tests.rb +26 -0
  35. data/tests/geos/tc_point.rb +1 -20
  36. data/tests/simple_cartesian/tc_point.rb +1 -0
  37. data/tests/simple_mercator/tc_point.rb +1 -0
  38. data/tests/simple_spherical/tc_point.rb +1 -0
  39. data/tests/tc_oneoff.rb +3 -2
  40. metadata +8 -4
  41. data/lib/rgeo/impl_helpers/serialization.rb +0 -130
@@ -94,11 +94,11 @@ static VALUE method_point_y(VALUE self)
94
94
  }
95
95
 
96
96
 
97
- static VALUE method_point_z(VALUE self)
97
+ static VALUE get_3d_point(VALUE self, int flag)
98
98
  {
99
99
  VALUE result = Qnil;
100
100
  const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
101
- if (self_geom && GEOSHasZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom) == 1) {
101
+ if (self_geom && RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->flags & flag) {
102
102
  const GEOSCoordSequence* coord_seq = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
103
103
  if (coord_seq) {
104
104
  double val;
@@ -111,25 +111,32 @@ static VALUE method_point_z(VALUE self)
111
111
  }
112
112
 
113
113
 
114
+ static VALUE method_point_z(VALUE self)
115
+ {
116
+ return get_3d_point(self, RGEO_FACTORYFLAGS_SUPPORTS_Z);
117
+ }
118
+
119
+
120
+ static VALUE method_point_m(VALUE self)
121
+ {
122
+ return get_3d_point(self, RGEO_FACTORYFLAGS_SUPPORTS_M);
123
+ }
124
+
125
+
114
126
  static VALUE method_point_eql(VALUE self, VALUE rhs)
115
127
  {
116
128
  VALUE result = rgeo_geos_klasses_and_factories_eql(self, rhs);
117
129
  if (RTEST(result)) {
118
- result = rgeo_geos_coordseqs_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs));
130
+ result = rgeo_geos_coordseqs_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs), RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
119
131
  }
120
132
  return result;
121
133
  }
122
134
 
123
135
 
124
- static VALUE cmethod_create(VALUE module, VALUE factory, VALUE x, VALUE y)
125
- {
126
- return rgeo_create_geos_point_2d(factory, rb_num2dbl(x), rb_num2dbl(y));
127
- }
128
-
129
-
130
- static VALUE cmethod_create3d(VALUE module, VALUE factory, VALUE x, VALUE y, VALUE z)
136
+ static VALUE cmethod_create(VALUE module, VALUE factory, VALUE x, VALUE y, VALUE z)
131
137
  {
132
- return rgeo_create_geos_point_3d(factory, rb_num2dbl(x), rb_num2dbl(y), rb_num2dbl(z));
138
+ return rgeo_create_geos_point(factory, rb_num2dbl(x), rb_num2dbl(y),
139
+ RGEO_FACTORY_DATA_PTR(factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M ? rb_num2dbl(z) : 0);
133
140
  }
134
141
 
135
142
 
@@ -137,39 +144,21 @@ void rgeo_init_geos_point(RGeo_Globals* globals)
137
144
  {
138
145
  VALUE geos_point_class = rb_define_class_under(globals->geos_module, "PointImpl", rb_const_get_at(globals->geos_module, rb_intern("GeometryImpl")));
139
146
 
140
- rb_define_module_function(geos_point_class, "create", cmethod_create, 3);
141
- rb_define_module_function(geos_point_class, "create3d", cmethod_create3d, 4);
147
+ rb_define_module_function(geos_point_class, "create", cmethod_create, 4);
142
148
 
143
149
  rb_define_method(geos_point_class, "eql?", method_point_eql, 1);
144
150
  rb_define_method(geos_point_class, "geometry_type", method_point_geometry_type, 0);
145
151
  rb_define_method(geos_point_class, "x", method_point_x, 0);
146
152
  rb_define_method(geos_point_class, "y", method_point_y, 0);
147
153
  rb_define_method(geos_point_class, "z", method_point_z, 0);
154
+ rb_define_method(geos_point_class, "m", method_point_m, 0);
148
155
  }
149
156
 
150
157
 
151
- VALUE rgeo_create_geos_point_2d(VALUE factory, double x, double y)
152
- {
153
- VALUE result = Qnil;
154
- GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(RGEO_CONTEXT_FROM_FACTORY(factory), 1, 2);
155
- if (coord_seq) {
156
- if (GEOSCoordSeq_setX_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, x)) {
157
- if (GEOSCoordSeq_setY_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, y)) {
158
- GEOSGeometry* geom = GEOSGeom_createPoint_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq);
159
- if (geom) {
160
- result = rgeo_wrap_geos_geometry(factory, geom, rb_const_get_at(RGEO_GLOBALS_FROM_FACTORY(factory)->geos_module, rb_intern("PointImpl")));
161
- }
162
- }
163
- }
164
- }
165
- return result;
166
- }
167
-
168
-
169
- VALUE rgeo_create_geos_point_3d(VALUE factory, double x, double y, double z)
158
+ VALUE rgeo_create_geos_point(VALUE factory, double x, double y, double z)
170
159
  {
171
160
  VALUE result = Qnil;
172
- GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(RGEO_CONTEXT_FROM_FACTORY(factory), 1, 2);
161
+ GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(RGEO_CONTEXT_FROM_FACTORY(factory), 1, 3);
173
162
  if (coord_seq) {
174
163
  if (GEOSCoordSeq_setX_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, x)) {
175
164
  if (GEOSCoordSeq_setY_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, y)) {
@@ -51,15 +51,10 @@ RGEO_BEGIN_C
51
51
  */
52
52
  void rgeo_init_geos_point(RGeo_Globals* globals);
53
53
 
54
- /*
55
- Creates a 2d point and returns the ruby object.
56
- */
57
- VALUE rgeo_create_geos_point_2d(VALUE factory, double x, double y);
58
-
59
54
  /*
60
55
  Creates a 3d point and returns the ruby object.
61
56
  */
62
- VALUE rgeo_create_geos_point_3d(VALUE factory, double x, double y, double z);
57
+ VALUE rgeo_create_geos_point(VALUE factory, double x, double y, double z);
63
58
 
64
59
 
65
60
  RGEO_END_C
@@ -54,7 +54,7 @@ static VALUE method_polygon_eql(VALUE self, VALUE rhs)
54
54
  {
55
55
  VALUE result = rgeo_geos_klasses_and_factories_eql(self, rhs);
56
56
  if (RTEST(result)) {
57
- result = rgeo_geos_polygons_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs));
57
+ result = rgeo_geos_polygons_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs), RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
58
58
  }
59
59
  return result;
60
60
  }
@@ -214,11 +214,11 @@ void rgeo_init_geos_polygon(RGeo_Globals* globals)
214
214
  }
215
215
 
216
216
 
217
- VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2)
217
+ VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
218
218
  {
219
219
  VALUE result = Qnil;
220
220
  if (geom1 && geom2) {
221
- result = rgeo_geos_coordseqs_eql(context, GEOSGetExteriorRing_r(context, geom1), GEOSGetExteriorRing_r(context, geom2));
221
+ result = rgeo_geos_coordseqs_eql(context, GEOSGetExteriorRing_r(context, geom1), GEOSGetExteriorRing_r(context, geom2), check_z);
222
222
  if (RTEST(result)) {
223
223
  int len1 = GEOSGetNumInteriorRings_r(context, geom1);
224
224
  int len2 = GEOSGetNumInteriorRings_r(context, geom2);
@@ -226,7 +226,7 @@ VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* ge
226
226
  if (len1 == len2) {
227
227
  int i;
228
228
  for (i=0; i<len1; ++i) {
229
- result = rgeo_geos_coordseqs_eql(context, GEOSGetInteriorRingN_r(context, geom1, i), GEOSGetInteriorRingN_r(context, geom2, i));
229
+ result = rgeo_geos_coordseqs_eql(context, GEOSGetInteriorRingN_r(context, geom1, i), GEOSGetInteriorRingN_r(context, geom2, i), check_z);
230
230
  if (!RTEST(result)) {
231
231
  break;
232
232
  }
@@ -58,7 +58,7 @@ void rgeo_init_geos_polygon(RGeo_Globals* globals);
58
58
  Returns Qtrue if the polygons are equal, Qfalse if they are inequal, or
59
59
  Qnil if an error occurs.
60
60
  */
61
- VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2);
61
+ VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
62
62
 
63
63
 
64
64
  RGEO_END_C
data/lib/rgeo.rb CHANGED
@@ -78,6 +78,7 @@ paths_ = [
78
78
  'errors',
79
79
  'features',
80
80
  'impl_helpers',
81
+ 'wkrep',
81
82
  'geos',
82
83
  'cartesian',
83
84
  'geography',
@@ -57,6 +57,8 @@ module RGeo
57
57
 
58
58
  def initialize(opts_={})
59
59
  @srid = opts_[:srid].to_i
60
+ @support_z = opts_[:support_z_coordinate] ? true : false
61
+ @support_m = opts_[:support_m_coordinate] ? true : false
60
62
  end
61
63
 
62
64
 
@@ -75,24 +77,38 @@ module RGeo
75
77
  end
76
78
 
77
79
 
80
+ # See ::RGeo::Features::Factory#has_capability?
81
+
82
+ def has_capability?(name_)
83
+ case name_
84
+ when :z_coordinate
85
+ @support_z
86
+ when :m_coordinate
87
+ @support_m
88
+ else
89
+ nil
90
+ end
91
+ end
92
+
93
+
78
94
  # See ::RGeo::Features::Factory#parse_wkt
79
95
 
80
96
  def parse_wkt(str_)
81
- ImplHelpers::Serialization.parse_wkt(str_, self)
97
+ WKRep::WKTParser.new(self, :support_higher_dimensions => true).parse(str_)
82
98
  end
83
99
 
84
100
 
85
101
  # See ::RGeo::Features::Factory#parse_wkb
86
102
 
87
103
  def parse_wkb(str_)
88
- ImplHelpers::Serialization.parse_wkb(str_, self)
104
+ WKRep::WKBParser.new(self).parse(str_)
89
105
  end
90
106
 
91
107
 
92
108
  # See ::RGeo::Features::Factory#point
93
109
 
94
- def point(x_, y_)
95
- SimplePointImpl.new(self, x_, y_) rescue nil
110
+ def point(x_, y_, *extra_)
111
+ SimplePointImpl.new(self, x_, y_, *extra_) rescue nil
96
112
  end
97
113
 
98
114
 
data/lib/rgeo/errors.rb CHANGED
@@ -53,6 +53,14 @@ module RGeo
53
53
  class InvalidGeometry < RGeoError
54
54
  end
55
55
 
56
+ # The specified capability is not supported
57
+ class UnsupportedCapability < RGeoError
58
+ end
59
+
60
+ # Parsing failed
61
+ class ParseError < RGeoError
62
+ end
63
+
56
64
  end
57
65
 
58
66
 
@@ -71,6 +71,36 @@ module RGeo
71
71
  end
72
72
 
73
73
 
74
+ # Determine support for the given capability, identified by a
75
+ # symbolic name. This method may be used to test this factory, and
76
+ # any features created by it, to determine whether they support
77
+ # certain capabilities or operations. Most queries return a boolean
78
+ # value, though some may return other values to indicate different
79
+ # levels of support. Generally speaking, if a query returns a false
80
+ # or nil value, support for that capability is not guaranteed, and
81
+ # calls related to that function may fail or raise exceptions.
82
+ #
83
+ # Each capability must have a symbolic name. Names that have no
84
+ # periods are considered well-known names and are reserved for use
85
+ # by RGeo. If you want to define your own capabilities, use a name
86
+ # that is namespaced, such as <tt>:'mycompany.mycapability'</tt>.
87
+ #
88
+ # Currently defined standard capabilities are:
89
+ #
90
+ # <tt>:z_coordinate</tt>::
91
+ # Supports a "z" coordinate. When an implementation supports
92
+ # z_coordinate, the Factory#epoint and Point#z methods are
93
+ # available.
94
+ # <tt>:m_coordinate</tt>::
95
+ # Supports a "m" coordinate. When an implementation supports
96
+ # m_coordinate, the Factory#epoint and Point#m methods are
97
+ # available.
98
+
99
+ def has_capability?(name_)
100
+ nil
101
+ end
102
+
103
+
74
104
  # Parse the given string in well-known-text format and return the
75
105
  # resulting feature. Returns nil if the string couldn't be parsed.
76
106
 
@@ -89,8 +119,12 @@ module RGeo
89
119
 
90
120
  # Create a feature of type Point.
91
121
  # The x and y parameters should be Float values.
122
+ #
123
+ # The extra parameters should be the Z and/or M coordinates, if the
124
+ # capabilities are supported. If both Z and M capabilities are
125
+ # supported, Z should be passed first.
92
126
 
93
- def point(x_, y_)
127
+ def point(x_, y_, *extra_)
94
128
  nil
95
129
  end
96
130
 
@@ -90,6 +90,28 @@ module RGeo
90
90
  end
91
91
 
92
92
 
93
+ # Returns the z-coordinate for this Point as a floating-point
94
+ # scalar value.
95
+ #
96
+ # This method may not be available if the point's factory does
97
+ # not support the <tt>z_coordinate</tt> capability.
98
+
99
+ def z
100
+ raise Errors::MethodUnimplemented
101
+ end
102
+
103
+
104
+ # Returns the m-coordinate for this Point as a floating-point
105
+ # scalar value.
106
+ #
107
+ # This method may not be available if the point's factory does
108
+ # not support the <tt>m_coordinate</tt> capability.
109
+
110
+ def m
111
+ raise Errors::MethodUnimplemented
112
+ end
113
+
114
+
93
115
  end
94
116
 
95
117
 
@@ -117,7 +117,7 @@ module RGeo
117
117
  #
118
118
  # === Notes
119
119
  #
120
- # Returns an object that supports the LineString interface, or nil
120
+ # Returns an object that supports the LinearRing interface, or nil
121
121
  # if the given n is out of range.
122
122
 
123
123
  def interior_ring_n(n_)
@@ -133,7 +133,6 @@ module RGeo
133
133
  end
134
134
 
135
135
 
136
-
137
136
  end
138
137
 
139
138
 
@@ -39,7 +39,7 @@ module RGeo
39
39
  module Features
40
40
 
41
41
 
42
- # These methods are available as class methods (not instance methods)
42
+ # These methods are available as module methods (not instance methods)
43
43
  # of the various feature types.
44
44
  # For example, you may determine whether a feature object is a
45
45
  # point by calling:
@@ -78,6 +78,21 @@ module RGeo
78
78
  alias_method :===, :check_type
79
79
 
80
80
 
81
+ # Returns true if this type is the same type or a subtype of the
82
+ # given type.
83
+
84
+ def subtype_of?(type_)
85
+ self == type_ || self.include?(type_)
86
+ end
87
+
88
+
89
+ # Returns the OpenGIS type name of this type.
90
+
91
+ def type_name
92
+ self.name.sub('RGeo::Features::', '')
93
+ end
94
+
95
+
81
96
  end
82
97
 
83
98
 
@@ -135,7 +150,14 @@ module RGeo
135
150
  force_new_ ? obj_.dup : obj_
136
151
  elsif ntype_ == type_
137
152
  if type_ == Point
138
- nfactory_.point(obj_.x, obj_.y)
153
+ extra_ = []
154
+ if nfactory_.has_capability?(:z_coordinate)
155
+ extra_ << (factory_.has_capability?(:z_coordinate) ? obj_.z : 0.0)
156
+ end
157
+ if nfactory_.has_capability?(:m_coordinate)
158
+ extra_ << (factory_.has_capability?(:m_coordinate) ? obj_.m : 0.0)
159
+ end
160
+ nfactory_.point(obj_.x, obj_.y, *extra_)
139
161
  elsif type_ == Line
140
162
  nfactory_.line(obj_.start_point, obj_.end_point)
141
163
  elsif type_ == LinearRing
@@ -165,24 +187,56 @@ module RGeo
165
187
  else
166
188
  nil
167
189
  end
168
- elsif ntype_ == Line && type_ == LineString
169
- if obj_.num_points == 2
190
+ elsif ntype_ == Point
191
+ nil
192
+ elsif ntype_ == Line
193
+ if type_ == LineString && obj_.num_points == 2
170
194
  nfactory_.line(obj_.point_n(0), obj_.point_n(1))
171
195
  else
172
196
  nil
173
197
  end
174
- elsif ntype_ == LinearRing && type_ == LineString
175
- nfactory_.linear_ring(obj_.points)
176
- elsif ntype_ == LineString && (type_ == Line || type_ == LinearRing)
177
- nfactory_.line_string(obj_.points)
178
- elsif ntype_ == MultiPoint && type_ == GeometryCollection
179
- nfactory_.multi_point(obj_)
180
- elsif ntype_ == MultiLineString && type_ == GeometryCollection
181
- nfactory_.multi_line_string(obj_)
182
- elsif ntype_ == MultiPolygon && type_ == GeometryCollection
183
- nfactory_.multi_polygon(obj_)
184
- elsif ntype_ == GeometryCollection && (type_ == MultiPoint || type_ == MultiLineString || type_ == MultiPolygon)
185
- nfactory_.collection(obj_)
198
+ elsif ntype_ == LinearRing
199
+ if type_ == LineString
200
+ nfactory_.linear_ring(obj_.points)
201
+ else
202
+ nil
203
+ end
204
+ elsif ntype_ == LineString
205
+ if type_ == Line || type_ == LinearRing
206
+ nfactory_.line_string(obj_.points)
207
+ else
208
+ nil
209
+ end
210
+ elsif ntype_ == MultiPoint
211
+ if type_ == Point
212
+ nfactory_.multi_point([obj_])
213
+ elsif type_ == GeometryCollection
214
+ nfactory_.multi_point(obj_)
215
+ else
216
+ nil
217
+ end
218
+ elsif ntype_ == MultiLineString
219
+ if type_ == Line || type_ == LinearRing || type_ == LineString
220
+ nfactory_.multi_line_string([obj_])
221
+ elsif type_ == GeometryCollection
222
+ nfactory_.multi_line_string(obj_)
223
+ else
224
+ nil
225
+ end
226
+ elsif ntype_ == MultiPolygon
227
+ if type_ == Polygon
228
+ nfactory_.multi_polygon([obj_])
229
+ elsif type_ == GeometryCollection
230
+ nfactory_.multi_polygon(obj_)
231
+ else
232
+ nil
233
+ end
234
+ elsif ntype_ == GeometryCollection
235
+ if type_ == MultiPoint || type_ == MultiLineString || type_ == MultiPolygon
236
+ nfactory_.collection(obj_)
237
+ else
238
+ nfactory_.collection([obj_])
239
+ end
186
240
  else
187
241
  nil
188
242
  end