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
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
  }