rgeo 0.1.13 → 0.1.14

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.
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
data/History.rdoc CHANGED
@@ -1,3 +1,14 @@
1
+ === 0.1.14 / 2010-11-04
2
+
3
+ * Introduced capability checking API.
4
+ * Standardized API and semantics for handling of points with Z and/or M coordinates.
5
+ * Fixed several problems with Z coordinates in GEOS.
6
+ * Fixed exceptions and wrong values returned from GEOS LineString#start_point and LineString#end_point.
7
+ * Fixed crash in GEOS LineString#point_n when the index was out of bounds.
8
+ * Fixed GEOS line string closed test.
9
+ * Implemented support for Z and M coordinates in GEOS, SimpleCartesian, SimpleMercator, and SimpleSpherical. GEOS and SimpleMercator support Z or M but not both at once, because the underlying GEOS library supports only 3 dimensions. SimpleCartesian and SimpleSpherical can support both at once.
10
+ * Implemented parsers and generators for WKT/WKB and EWKT/EWKB in Ruby, providing full support for all generally used cases including 3 and 4 dimensional data and embedded SRIDs. This implementation is used by default by all feature implementations except GEOS, which continues to use its own internal WKT/WKB implementation unless the Ruby implementation is invoked explicitly.
11
+
1
12
  === 0.1.13 / 2010-10-26
2
13
 
3
14
  * Reworked the way casting is done. Casting has two dimensions: factory casting and type casting, either or both of which can be done at once. Implemented a standard casting algorithm to handle these cases, and an override mechanism for factories that want to do some of their own casting. Removed Factory#cast and Geometry#cast, and implemented a global Features::cast entry point instead.
data/Version CHANGED
@@ -1 +1 @@
1
- 0.1.13
1
+ 0.1.14
@@ -371,69 +371,64 @@ const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj)
371
371
  }
372
372
 
373
373
 
374
- VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2)
374
+ VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
375
375
  {
376
376
  VALUE result = Qnil;
377
377
  if (geom1 && geom2) {
378
378
  const GEOSCoordSequence* cs1 = GEOSGeom_getCoordSeq_r(context, geom1);
379
379
  const GEOSCoordSequence* cs2 = GEOSGeom_getCoordSeq_r(context, geom2);
380
380
  if (cs1 && cs2) {
381
- char hasz1 = GEOSHasZ_r(context, geom1);
382
- char hasz2 = GEOSHasZ_r(context, geom2);
383
- if (hasz1 != 2 && hasz2 != 2) {
384
- if (hasz1 == hasz2) {
385
- unsigned int len1 = 0;
386
- unsigned int len2 = 0;
387
- if (GEOSCoordSeq_getSize_r(context, cs1, &len1) && GEOSCoordSeq_getSize_r(context, cs2, &len2)) {
388
- if (len1 == len2) {
389
- result = Qtrue;
390
- unsigned int i;
391
- double val1, val2;
392
- for (i=0; i<len1; ++i) {
393
- if (GEOSCoordSeq_getX_r(context, cs1, i, &val1) && GEOSCoordSeq_getX_r(context, cs2, i, &val2)) {
381
+ unsigned int len1 = 0;
382
+ unsigned int len2 = 0;
383
+ if (GEOSCoordSeq_getSize_r(context, cs1, &len1) && GEOSCoordSeq_getSize_r(context, cs2, &len2)) {
384
+ if (len1 == len2) {
385
+ result = Qtrue;
386
+ unsigned int i;
387
+ double val1, val2;
388
+ for (i=0; i<len1; ++i) {
389
+ if (GEOSCoordSeq_getX_r(context, cs1, i, &val1) && GEOSCoordSeq_getX_r(context, cs2, i, &val2)) {
390
+ if (val1 == val2) {
391
+ if (GEOSCoordSeq_getY_r(context, cs1, i, &val1) && GEOSCoordSeq_getY_r(context, cs2, i, &val2)) {
394
392
  if (val1 == val2) {
395
- if (GEOSCoordSeq_getY_r(context, cs1, i, &val1) && GEOSCoordSeq_getY_r(context, cs2, i, &val2)) {
396
- if (val1 == val2) {
397
- if (hasz1) {
398
- if (GEOSCoordSeq_getZ_r(context, cs1, i, &val1) && GEOSCoordSeq_getZ_r(context, cs2, i, &val2)) {
399
- if (val1 != val2) {
400
- result = Qfalse;
401
- break;
402
- }
403
- }
404
- else { // Failed to get Z coords
405
- result = Qnil;
406
- break;
407
- }
408
- }
393
+ if (check_z) {
394
+ val1 = 0;
395
+ if (!GEOSCoordSeq_getZ_r(context, cs1, i, &val1)) {
396
+ result = Qnil;
397
+ break;
398
+ }
399
+ val2 = 0;
400
+ if (!GEOSCoordSeq_getZ_r(context, cs2, i, &val2)) {
401
+ result = Qnil;
402
+ break;
409
403
  }
410
- else { // Y coords are different
404
+ if (val1 != val2) {
411
405
  result = Qfalse;
412
406
  break;
413
407
  }
414
408
  }
415
- else { // Failed to get Y coords
416
- result = Qnil;
417
- break;
418
- }
419
409
  }
420
- else { // X coords are different
410
+ else { // Y coords are different
421
411
  result = Qfalse;
422
412
  break;
423
413
  }
424
414
  }
425
- else { // Failed to get X coords
415
+ else { // Failed to get Y coords
426
416
  result = Qnil;
427
417
  break;
428
418
  }
429
- } // Iteration over coords
419
+ }
420
+ else { // X coords are different
421
+ result = Qfalse;
422
+ break;
423
+ }
430
424
  }
431
- else { // Lengths are different
432
- result = Qfalse;
425
+ else { // Failed to get X coords
426
+ result = Qnil;
427
+ break;
433
428
  }
434
- }
429
+ } // Iteration over coords
435
430
  }
436
- else { // Z coord existence is different
431
+ else { // Lengths are different
437
432
  result = Qfalse;
438
433
  }
439
434
  }
@@ -72,6 +72,9 @@ typedef struct {
72
72
  } RGeo_FactoryData;
73
73
 
74
74
  #define RGEO_FACTORYFLAGS_LENIENT_MULTIPOLYGON 1
75
+ #define RGEO_FACTORYFLAGS_SUPPORTS_Z 2
76
+ #define RGEO_FACTORYFLAGS_SUPPORTS_M 4
77
+ #define RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M 6
75
78
 
76
79
 
77
80
  // Wrapped structure for Geometry objects.
@@ -196,7 +199,7 @@ const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj);
196
199
  Returns Qtrue if the two coordinate sequences are equal, Qfalse
197
200
  if they are inequal, or Qnil if an error occurs.
198
201
  */
199
- VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2);
202
+ VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
200
203
 
201
204
  /*
202
205
  Compares the ruby classes and geometry factories of the two given ruby
@@ -151,7 +151,7 @@ static VALUE method_geometry_collection_eql(VALUE self, VALUE rhs)
151
151
  {
152
152
  VALUE result = rgeo_geos_klasses_and_factories_eql(self, rhs);
153
153
  if (RTEST(result)) {
154
- result = rgeo_geos_geometry_collections_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs));
154
+ result = rgeo_geos_geometry_collections_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);
155
155
  }
156
156
  return result;
157
157
  }
@@ -390,7 +390,7 @@ void rgeo_init_geos_geometry_collection(RGeo_Globals* globals)
390
390
  /**** OTHER PUBLIC FUNCTIONS ****/
391
391
 
392
392
 
393
- VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2)
393
+ VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
394
394
  {
395
395
  VALUE result = Qnil;
396
396
  if (geom1 && geom2) {
@@ -412,16 +412,16 @@ VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOS
412
412
  case GEOS_POINT:
413
413
  case GEOS_LINESTRING:
414
414
  case GEOS_LINEARRING:
415
- result = rgeo_geos_coordseqs_eql(context, sub_geom1, sub_geom2);
415
+ result = rgeo_geos_coordseqs_eql(context, sub_geom1, sub_geom2, check_z);
416
416
  break;
417
417
  case GEOS_POLYGON:
418
- result = rgeo_geos_polygons_eql(context, sub_geom1, sub_geom2);
418
+ result = rgeo_geos_polygons_eql(context, sub_geom1, sub_geom2, check_z);
419
419
  break;
420
420
  case GEOS_GEOMETRYCOLLECTION:
421
421
  case GEOS_MULTIPOINT:
422
422
  case GEOS_MULTILINESTRING:
423
423
  case GEOS_MULTIPOLYGON:
424
- result = rgeo_geos_geometry_collections_eql(context, sub_geom1, sub_geom2);
424
+ result = rgeo_geos_geometry_collections_eql(context, sub_geom1, sub_geom2, check_z);
425
425
  break;
426
426
  default:
427
427
  result = Qnil;
@@ -61,7 +61,7 @@ void rgeo_init_geos_geometry_collection(RGeo_Globals* globals);
61
61
  Returns Qtrue if the contents of the two geometry collections are equal,
62
62
  Qfalse if they are inequal, or Qnil if an error occurs.
63
63
  */
64
- VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2);
64
+ VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
65
65
 
66
66
 
67
67
  RGEO_END_C
@@ -109,6 +109,27 @@ static VALUE method_line_string_num_points(VALUE self)
109
109
  }
110
110
 
111
111
 
112
+ static VALUE get_point_from_coordseq(VALUE self, const GEOSCoordSequence* coord_seq, unsigned int i, char has_z)
113
+ {
114
+ VALUE result = Qnil;
115
+ double x, y, z;
116
+ if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &x)) {
117
+ if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &y)) {
118
+ if (has_z) {
119
+ if (!GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &z)) {
120
+ z = 0.0;
121
+ }
122
+ }
123
+ else {
124
+ z = 0.0;
125
+ }
126
+ result = rgeo_create_geos_point(RGEO_FACTORY_FROM_GEOMETRY(self), x, y, z);
127
+ }
128
+ }
129
+ return result;
130
+ }
131
+
132
+
112
133
  static VALUE method_line_string_point_n(VALUE self, VALUE n)
113
134
  {
114
135
  VALUE result = Qnil;
@@ -116,18 +137,15 @@ static VALUE method_line_string_point_n(VALUE self, VALUE n)
116
137
  if (self_geom) {
117
138
  const GEOSCoordSequence* coord_seq = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
118
139
  if (coord_seq) {
119
- char has_z = GEOSHasZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom) == 1 ? 1 : 0;
120
- unsigned int i = NUM2INT(n);
121
- double x, y, z;
122
- if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &x)) {
123
- if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &y)) {
124
- if (has_z) {
125
- if (GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &z)) {
126
- result = rgeo_create_geos_point_3d(RGEO_FACTORY_FROM_GEOMETRY(self), x, y, z);
127
- }
128
- }
129
- else {
130
- result = rgeo_create_geos_point_2d(RGEO_FACTORY_FROM_GEOMETRY(self), x, y);
140
+ char has_z = (char)(RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
141
+ int si = NUM2INT(n);
142
+ if (si >= 0) {
143
+ unsigned int i = si;
144
+ unsigned int size;
145
+ if (GEOSCoordSeq_getSize_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, &size)) {
146
+ if (i < size) {
147
+ unsigned int dims;
148
+ result = get_point_from_coordseq(self, coord_seq, i, has_z);
131
149
  }
132
150
  }
133
151
  }
@@ -144,22 +162,16 @@ static VALUE method_line_string_points(VALUE self)
144
162
  if (self_geom) {
145
163
  const GEOSCoordSequence* coord_seq = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
146
164
  if (coord_seq) {
147
- char has_z = GEOSHasZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom) == 1 ? 1 : 0;
148
- int count = GEOSGetNumCoordinates_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
149
- result = rb_ary_new2(count);
150
- double x, y, z;
151
- int i;
152
- for (i=0; i<count; ++i) {
153
- if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &x)) {
154
- if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &y)) {
155
- if (has_z) {
156
- if (GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, i, &z)) {
157
- rb_ary_store(result, i, rgeo_create_geos_point_3d(RGEO_FACTORY_FROM_GEOMETRY(self), x, y, z));
158
- }
159
- }
160
- else {
161
- rb_ary_store(result, i, rgeo_create_geos_point_2d(RGEO_FACTORY_FROM_GEOMETRY(self), x, y));
162
- }
165
+ char has_z = (char)(RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
166
+ unsigned int size;
167
+ if (GEOSCoordSeq_getSize_r(RGEO_CONTEXT_FROM_GEOMETRY(self), coord_seq, &size)) {
168
+ result = rb_ary_new2(size);
169
+ double x, y, z;
170
+ unsigned int i;
171
+ for (i=0; i<size; ++i) {
172
+ VALUE point = get_point_from_coordseq(self, coord_seq, i, has_z);
173
+ if (!NIL_P(point)) {
174
+ rb_ary_store(result, i, point);
163
175
  }
164
176
  }
165
177
  }
@@ -171,7 +183,7 @@ static VALUE method_line_string_points(VALUE self)
171
183
 
172
184
  static VALUE method_line_string_start_point(VALUE self)
173
185
  {
174
- return method_line_string_point_n(self, 0);
186
+ return method_line_string_point_n(self, INT2NUM(0));
175
187
  }
176
188
 
177
189
 
@@ -182,7 +194,7 @@ static VALUE method_line_string_end_point(VALUE self)
182
194
  if (self_geom) {
183
195
  unsigned int n = GEOSGetNumCoordinates_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
184
196
  if (n > 0) {
185
- result = method_line_string_point_n(self, n-1);
197
+ result = method_line_string_point_n(self, INT2NUM(n-1));
186
198
  }
187
199
  }
188
200
  return result;
@@ -221,7 +233,7 @@ static VALUE method_line_string_eql(VALUE self, VALUE rhs)
221
233
  {
222
234
  VALUE result = rgeo_geos_klasses_and_factories_eql(self, rhs);
223
235
  if (RTEST(result)) {
224
- result = rgeo_geos_coordseqs_eql(RGEO_CONTEXT_FROM_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(self), RGEO_GET_GEOS_GEOMETRY(rhs));
236
+ 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);
225
237
  }
226
238
  return result;
227
239
  }
@@ -231,45 +243,66 @@ static GEOSCoordSequence* coord_seq_from_array(VALUE factory, VALUE array, char
231
243
  {
232
244
  Check_Type(array, T_ARRAY);
233
245
  VALUE point_type = rb_const_get_at(RGEO_GLOBALS_FROM_FACTORY(factory)->features_module, rb_intern("Point"));
234
- unsigned int orig_len = (unsigned int)RARRAY_LEN(array);
235
- const GEOSGeometry** geoms = ALLOC_N(const GEOSGeometry*, orig_len == 0 ? 1 : orig_len);
236
- if (!geoms) {
246
+ unsigned int len = (unsigned int)RARRAY_LEN(array);
247
+ char has_z = (char)(RGEO_FACTORY_DATA_PTR(factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
248
+ unsigned int dims = has_z ? 3 : 2;
249
+ double* coords = ALLOC_N(double, len == 0 ? 1 : len * dims);
250
+ if (!coords) {
237
251
  return NULL;
238
252
  }
239
- char has_z = 0;
253
+ GEOSContextHandle_t context = RGEO_CONTEXT_FROM_FACTORY(factory);
240
254
  unsigned int i;
241
- for (i=0; i<orig_len; ++i) {
255
+ for (i=0; i<len; ++i) {
256
+ char good = 0;
242
257
  const GEOSGeometry* entry_geom = rgeo_convert_to_geos_geometry(factory, rb_ary_entry(array, i), point_type);
243
- if (!entry_geom) {
244
- free(geoms);
258
+ if (entry_geom) {
259
+ const GEOSCoordSequence* entry_cs = GEOSGeom_getCoordSeq_r(context, entry_geom);
260
+ if (entry_cs) {
261
+ double x;
262
+ if (GEOSCoordSeq_getX_r(context, entry_cs, 0, &x)) {
263
+ coords[i*dims] = x;
264
+ if (GEOSCoordSeq_getY_r(context, entry_cs, 0, &x)) {
265
+ coords[i*dims+1] = x;
266
+ good = 1;
267
+ if (has_z) {
268
+ if (GEOSCoordSeq_getZ_r(context, entry_cs, 0, &x)) {
269
+ coords[i*dims+2] = x;
270
+ }
271
+ else {
272
+ good = 0;
273
+ }
274
+ }
275
+ }
276
+ }
277
+ }
278
+ }
279
+ if (!good) {
280
+ free(coords);
245
281
  return NULL;
246
282
  }
247
- geoms[i] = entry_geom;
248
- if (GEOSHasZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), entry_geom) == 1) {
249
- has_z = 1;
283
+ }
284
+ if (len > 0 && close) {
285
+ if (coords[0] == coords[(len-1)*dims] && coords[1] == coords[(len-1)*dims+1]) {
286
+ close = 0;
250
287
  }
251
288
  }
252
- unsigned int len = orig_len;
253
- if (orig_len > 0 && close && GEOSEquals_r(RGEO_CONTEXT_FROM_FACTORY(factory), geoms[0], geoms[orig_len-1]) != 1) {
254
- ++len;
289
+ else {
290
+ close = 0;
255
291
  }
256
- GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(RGEO_CONTEXT_FROM_FACTORY(factory), len, has_z ? 3 : 2);
292
+ GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(context, len + close, 3);
257
293
  if (coord_seq) {
258
294
  for (i=0; i<len; ++i) {
259
- const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_FACTORY(factory), geoms[i == orig_len ? 0 : i]);
260
- double x;
261
- if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
262
- GEOSCoordSeq_setX_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, i, x);
263
- }
264
- if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
265
- GEOSCoordSeq_setY_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, i, x);
266
- }
267
- if (has_z && GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
268
- GEOSCoordSeq_setZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, i, x);
269
- }
295
+ GEOSCoordSeq_setX_r(context, coord_seq, i, coords[i*dims]);
296
+ GEOSCoordSeq_setY_r(context, coord_seq, i, coords[i*dims+1]);
297
+ GEOSCoordSeq_setZ_r(context, coord_seq, i, has_z ? coords[i*dims+2] : 0);
298
+ }
299
+ if (close) {
300
+ GEOSCoordSeq_setX_r(context, coord_seq, len, coords[0]);
301
+ GEOSCoordSeq_setY_r(context, coord_seq, len, coords[1]);
302
+ GEOSCoordSeq_setZ_r(context, coord_seq, len, has_z ? coords[2] : 0);
270
303
  }
271
304
  }
272
- free(geoms);
305
+ free(coords);
273
306
  return coord_seq;
274
307
  }
275
308
 
@@ -302,56 +335,50 @@ static VALUE cmethod_create_linear_ring(VALUE module, VALUE factory, VALUE array
302
335
  }
303
336
 
304
337
 
338
+ static void populate_geom_into_coord_seq(GEOSContextHandle_t context, const GEOSGeometry* geom, GEOSCoordSequence* coord_seq, unsigned int i, char has_z)
339
+ {
340
+ const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq_r(context, geom);
341
+ double x = 0;
342
+ if (cs) {
343
+ GEOSCoordSeq_getX_r(context, cs, 0, &x);
344
+ }
345
+ GEOSCoordSeq_setX_r(context, coord_seq, i, x);
346
+ x = 0;
347
+ if (cs) {
348
+ GEOSCoordSeq_getY_r(context, cs, 0, &x);
349
+ }
350
+ GEOSCoordSeq_setY_r(context, coord_seq, i, x);
351
+ x = 0;
352
+ if (has_z && cs) {
353
+ GEOSCoordSeq_getZ_r(context, cs, 0, &x);
354
+ }
355
+ GEOSCoordSeq_setZ_r(context, coord_seq, i, x);
356
+ }
357
+
358
+
305
359
  static VALUE cmethod_create_line(VALUE module, VALUE factory, VALUE start, VALUE end)
306
360
  {
307
361
  VALUE result = Qnil;
308
- char has_z = 0;
362
+ char has_z = (char)(RGEO_FACTORY_DATA_PTR(factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
309
363
  VALUE point_type = rb_const_get_at(RGEO_GLOBALS_FROM_FACTORY(factory)->features_module, rb_intern("Point"));
364
+ GEOSContextHandle_t context = RGEO_CONTEXT_FROM_FACTORY(factory);
310
365
 
311
366
  const GEOSGeometry* start_geom = rgeo_convert_to_geos_geometry(factory, start, point_type);
312
- if (!start_geom) {
313
- return Qnil;
314
- }
315
- if (GEOSHasZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), start_geom) == 1) {
316
- has_z = 1;
317
- }
318
- const GEOSGeometry* end_geom = rgeo_convert_to_geos_geometry(factory, end, point_type);
319
- if (!end_geom) {
320
- return Qnil;
321
- }
322
- if (GEOSHasZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), end_geom) == 1) {
323
- has_z = 1;
324
- }
325
-
326
- GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(RGEO_CONTEXT_FROM_FACTORY(factory), 2, has_z ? 3 : 2);
327
- if (coord_seq) {
328
- const GEOSCoordSequence* cs;
329
- double x;
330
- cs = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_FACTORY(factory), start_geom);
331
- if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
332
- GEOSCoordSeq_setX_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, x);
333
- }
334
- if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
335
- GEOSCoordSeq_setY_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, x);
336
- }
337
- if (has_z && GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
338
- GEOSCoordSeq_setZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 0, x);
339
- }
340
- cs = GEOSGeom_getCoordSeq_r(RGEO_CONTEXT_FROM_FACTORY(factory), end_geom);
341
- if (GEOSCoordSeq_getX_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
342
- GEOSCoordSeq_setX_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 1, x);
343
- }
344
- if (GEOSCoordSeq_getY_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
345
- GEOSCoordSeq_setY_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 1, x);
346
- }
347
- if (has_z && GEOSCoordSeq_getZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), cs, 0, &x)) {
348
- GEOSCoordSeq_setZ_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq, 1, x);
349
- }
350
- GEOSGeometry* geom = GEOSGeom_createLineString_r(RGEO_CONTEXT_FROM_FACTORY(factory), coord_seq);
351
- if (geom) {
352
- result = rgeo_wrap_geos_geometry(factory, geom, rb_const_get_at(RGEO_GLOBALS_FROM_FACTORY(factory)->geos_module, rb_intern("LineImpl")));
367
+ if (start_geom) {
368
+ const GEOSGeometry* end_geom = rgeo_convert_to_geos_geometry(factory, end, point_type);
369
+ if (end_geom) {
370
+ GEOSCoordSequence* coord_seq = GEOSCoordSeq_create_r(context, 2, 3);
371
+ if (coord_seq) {
372
+ populate_geom_into_coord_seq(context, start_geom, coord_seq, 0, has_z);
373
+ populate_geom_into_coord_seq(context, end_geom, coord_seq, 1, has_z);
374
+ GEOSGeometry* geom = GEOSGeom_createLineString_r(context, coord_seq);
375
+ if (geom) {
376
+ result = rgeo_wrap_geos_geometry(factory, geom, rb_const_get_at(RGEO_GLOBALS_FROM_FACTORY(factory)->geos_module, rb_intern("LineImpl")));
377
+ }
378
+ }
353
379
  }
354
380
  }
381
+
355
382
  return result;
356
383
  }
357
384
 
@@ -437,26 +464,12 @@ VALUE rgeo_is_geos_line_string_closed(GEOSContextHandle_t context, const GEOSGeo
437
464
  if (GEOSCoordSeq_getX_r(context, coord_seq, n-1, &x2)) {
438
465
  if (x1 == x2) {
439
466
  if (GEOSCoordSeq_getY_r(context, coord_seq, 0, &y1)) {
440
- if (GEOSCoordSeq_getY_r(context, coord_seq, n-2, &y2)) {
441
- if (y1 == y2) {
442
- if (GEOSHasZ_r(context, geom) == 1) {
443
- if (GEOSCoordSeq_getZ_r(context, coord_seq, 0, &z1)) {
444
- if (GEOSCoordSeq_getZ_r(context, coord_seq, 0, &z2)) {
445
- result = z1 == z2 ? Qtrue : Qfalse;
446
- }
447
- }
448
- }
449
- else { // Doesn't have Z coordinate
450
- result = Qtrue;
451
- }
452
- }
453
- else { // Y coordinates are different
454
- result = Qfalse;
455
- }
467
+ if (GEOSCoordSeq_getY_r(context, coord_seq, n-1, &y2)) {
468
+ result = y1 == y2 ? Qtrue : Qfalse;
456
469
  }
457
470
  }
458
471
  }
459
- else { // X coordinates are different
472
+ else {
460
473
  result = Qfalse;
461
474
  }
462
475
  }