rgeo 0.3.1 → 0.3.2

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.
@@ -1,3 +1,12 @@
1
+ === 0.3.2 / 2011-08-11
2
+
3
+ * Some objects can now be serialized and deserialized via Marshal or YAML. Supported objects include OGC coordinate systems, Proj4 coordinate systems, and WKRep parsers/generators. Factories and geometries will be supported shortly.
4
+ * The GEOS CAPI implementation can now use prepared geometries to speed up certain operations. The GEOS FFI implementation will do the same shortly.
5
+ * Calling dup on a Proj4 object caused a segfault. Fixed.
6
+ * Fixed an exception in RGeo::Cartesian::BoundingBox#to_geometry. (Thanks to Travis Dempsey.)
7
+ * WKTGenerator generated incorrect tag names for subtypes of LineString. Fixed.
8
+ * Installation automatically finds the KyngChaos GEOS and Proj4 frameworks for Mac OS X. (Thanks to benchi.)
9
+
1
10
  === 0.3.1 / 2011-05-24
2
11
 
3
12
  * Running a == operator comparison between a geometry and a non-geometry caused an exception for some implementations. Fixed. (Reported by Daniel Hackney.)
@@ -39,15 +39,18 @@ Several optional modules are currently available:
39
39
  * <b>activerecord-postgis-adapter</b>
40
40
  * and more to come...
41
41
 
42
+ Need help? Join the rgeo-users google group at:
43
+ http://groups.google.com/group/rgeo-users
44
+
42
45
  === Dependencies
43
46
 
44
47
  RGeo is known to work with the following Ruby implementations:
45
48
 
46
49
  * Standard "MRI" Ruby 1.8.7 or later. (1.9.2 or later preferred.)
47
50
  * Rubinius 1.1 or later.
48
- * Partial support for JRuby 1.5 or later, but a bunch of features are
49
- missing or not yet stable because GEOS and Proj integration is not
50
- yet stable in JRuby. This is high-priority ongoing work.
51
+ * Partial support for JRuby 1.6.3 or later. The FFI implementation of
52
+ GEOS is available (ffi-geos gem is required) but CAPI is not.
53
+ Proj4 support is expected in the future.
51
54
 
52
55
  Some features also require the following:
53
56
 
@@ -71,7 +74,10 @@ Install RGeo as a gem:
71
74
 
72
75
  Note: By default, the gem installation looks for the GEOS library in the
73
76
  following locations: <tt>/usr/local</tt>, <tt>/usr/local/geos</tt>,
74
- <tt>/opt/local</tt>, <tt>/opt/geos</tt>, <tt>/opt</tt>, <tt>/usr</tt>.
77
+ <tt>/opt/local</tt>, <tt>/opt/geos</tt>, <tt>/opt</tt>, <tt>/usr</tt>,
78
+ and <tt>/Library/Frameworks/GEOS.framework/unix</tt>. In other words,
79
+ MacPorts, Homebrew, the Kyngchaos port, and building from source to
80
+ /usr/local are supported out of the box.
75
81
 
76
82
  If GEOS has been installed in a different location, you must provide its
77
83
  installation prefix directory using the "--with-geos-dir" option. This
@@ -83,7 +89,8 @@ switch, from the switches interpreted by the gem command. For example:
83
89
  Similarly, the gem installation looks for the Proj4 library in the
84
90
  following locations by default: <tt>/usr/local</tt>,
85
91
  <tt>/usr/local/proj</tt>, <tt>/usr/local/proj4</tt>, <tt>/opt/local</tt>,
86
- <tt>/opt/proj</tt>, <tt>/opt/proj4</tt>, <tt>/opt</tt>, <tt>/usr</tt>.
92
+ <tt>/opt/proj</tt>, <tt>/opt/proj4</tt>, <tt>/opt</tt>, <tt>/usr</tt>,
93
+ and <tt>/Library/Frameworks/PROJ.framework/unix</tt>.
87
94
 
88
95
  If Proj4 is installed in a different location, you must provide its
89
96
  installation prefix directory using the "--with-proj-dir" option.
@@ -93,7 +100,7 @@ installation prefix directory using the "--with-proj-dir" option.
93
100
  The RGeo suite of tools is evolving rapidly. The current to-do list for
94
101
  the core library includes:
95
102
 
96
- * YAML and Marshal serialization support.
103
+ * YAML and Marshal serialization support across all major entities.
97
104
  * Better JRuby support.
98
105
  * Ellipsoidal geography implementation, possibly utilizing geographiclib.
99
106
  * Windows build support.
@@ -102,7 +109,7 @@ Each of the current add-on modules also has its own feature roadmap, and
102
109
  we are planning on introducing more add-on modules, including:
103
110
 
104
111
  * GeoRSS and KML format support.
105
- * Integration with the SimpleGeo API.
112
+ * Integration with third-party APIs.
106
113
  * Possible additional ActiveRecord adapters.
107
114
 
108
115
  === Development and support
@@ -115,6 +122,8 @@ Contributions are welcome. Fork the project on Github.
115
122
 
116
123
  Report bugs on Github issues at http://github.org/dazuma/rgeo/issues
117
124
 
125
+ Support available on the rgeo-users google group at http://groups.google.com/group/rgeo-users
126
+
118
127
  Contact the author at dazuma at gmail dot com.
119
128
 
120
129
  === Acknowledgments
@@ -129,6 +138,9 @@ transformations. These libraries are maintained by the Open Source
129
138
  Geospatial Foundation; more information is available on OSGeo's web site
130
139
  (http://www.osgeo.org).
131
140
 
141
+ JRuby support is made possible by the ffi-geos (and upcoming ffi-proj4)
142
+ gems, by J Smith (http://github.com/dark-panda).
143
+
132
144
  === License
133
145
 
134
146
  Copyright 2010-2011 Daniel Azuma
data/Version CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
@@ -49,6 +49,7 @@ else
49
49
  '/opt/local/include',
50
50
  '/opt/geos/include',
51
51
  '/opt/include',
52
+ '/Library/Frameworks/GEOS.framework/unix/include',
52
53
  ::Config::CONFIG['includedir'],
53
54
  '/usr/include',
54
55
  ]
@@ -59,6 +60,7 @@ else
59
60
  '/opt/local/lib',
60
61
  '/opt/geos/lib',
61
62
  '/opt/lib',
63
+ '/Library/Frameworks/GEOS.framework/unix/lib',
62
64
  ::Config::CONFIG['libdir'],
63
65
  '/usr/lib',
64
66
  ]
@@ -74,6 +76,8 @@ else
74
76
  else
75
77
  $libs.gsub!(' -lgeos -lgeos_c', '')
76
78
  end
79
+ have_func('GEOSPreparedContains_r', 'geos_c.h')
80
+ have_func('GEOSPreparedDisjoint_r', 'geos_c.h')
77
81
  end
78
82
  unless found_geos_
79
83
  puts "**** WARNING: Unable to find GEOS headers or GEOS version is too old."
@@ -95,6 +95,12 @@ static void destroy_geometry_func(RGeo_GeometryData* data)
95
95
  if (data->geom) {
96
96
  GEOSGeom_destroy_r(data->geos_context, data->geom);
97
97
  }
98
+ const GEOSPreparedGeometry* prep = data->prep;
99
+ if (prep && prep != (const GEOSPreparedGeometry*)1 && prep != (const GEOSPreparedGeometry*)2 &&
100
+ prep != (const GEOSPreparedGeometry*)3)
101
+ {
102
+ GEOSPreparedGeom_destroy_r(data->geos_context, prep);
103
+ }
98
104
  free(data);
99
105
  }
100
106
 
@@ -323,8 +329,10 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
323
329
  if (geom) {
324
330
  GEOSSetSRID_r(factory_context, geom, factory_data->srid);
325
331
  }
326
- data->geom = geom;
327
332
  data->geos_context = factory_context;
333
+ data->geom = geom;
334
+ data->prep = factory_data && ((factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC) != 0) ?
335
+ (GEOSPreparedGeometry*)1 : NULL;
328
336
  data->factory = factory;
329
337
  data->klasses = klasses;
330
338
  result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data);
@@ -380,8 +388,13 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
380
388
  *klasses = CLASS_OF(object);
381
389
  }
382
390
  }
383
- object_data->geom = NULL;
391
+ const GEOSPreparedGeometry* prep = object_data->prep;
392
+ if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
393
+ GEOSPreparedGeom_destroy_r(object_data->geos_context, prep);
394
+ }
384
395
  object_data->geos_context = NULL;
396
+ object_data->geom = NULL;
397
+ object_data->prep = NULL;
385
398
  object_data->factory = Qnil;
386
399
  object_data->klasses = Qnil;
387
400
  }
@@ -101,6 +101,7 @@ typedef struct {
101
101
  #define RGEO_FACTORYFLAGS_SUPPORTS_Z 2
102
102
  #define RGEO_FACTORYFLAGS_SUPPORTS_M 4
103
103
  #define RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M 6
104
+ #define RGEO_FACTORYFLAGS_PREPARE_HEURISTIC 8
104
105
 
105
106
 
106
107
  /*
@@ -125,8 +126,9 @@ typedef struct {
125
126
  here so the destroy_geometry_func can get to it.
126
127
  */
127
128
  typedef struct {
128
- GEOSGeometry* geom;
129
129
  GEOSContextHandle_t geos_context;
130
+ GEOSGeometry* geom;
131
+ const GEOSPreparedGeometry* prep;
130
132
  VALUE factory;
131
133
  VALUE klasses;
132
134
  } RGeo_GeometryData;
@@ -101,6 +101,36 @@ static int compute_dimension(GEOSContextHandle_t context, const GEOSGeometry* ge
101
101
  }
102
102
 
103
103
 
104
+ // Returns a prepared geometry, honoring the preparation policy.
105
+
106
+ static const GEOSPreparedGeometry* rgeo_request_prepared_geometry(RGeo_GeometryData* object_data)
107
+ {
108
+ const GEOSPreparedGeometry* prep = object_data->prep;
109
+ if (prep == (const GEOSPreparedGeometry*)1) {
110
+ object_data->prep = (GEOSPreparedGeometry*)2;
111
+ prep = NULL;
112
+ }
113
+ else if (prep == (const GEOSPreparedGeometry*)2) {
114
+ if (object_data->geom) {
115
+ prep = GEOSPrepare_r(object_data->geos_context, object_data->geom);
116
+ }
117
+ else {
118
+ prep = NULL;
119
+ }
120
+ if (prep) {
121
+ object_data->prep = prep;
122
+ }
123
+ else {
124
+ object_data->prep = (const GEOSPreparedGeometry*)3;
125
+ }
126
+ }
127
+ else if (prep == (const GEOSPreparedGeometry*)3) {
128
+ prep = NULL;
129
+ }
130
+ return prep;
131
+ }
132
+
133
+
104
134
  /**** RUBY METHOD DEFINITIONS ****/
105
135
 
106
136
 
@@ -123,6 +153,34 @@ static VALUE method_geometry_set_factory(VALUE self, VALUE factory)
123
153
  }
124
154
 
125
155
 
156
+ static VALUE method_geometry_prepared_p(VALUE self)
157
+ {
158
+ const GEOSPreparedGeometry* prep = RGEO_GEOMETRY_DATA_PTR(self)->prep;
159
+ return (prep && prep != (const GEOSPreparedGeometry*)1 &&
160
+ prep != (const GEOSPreparedGeometry*)2 &&
161
+ prep != (GEOSPreparedGeometry*)3) ? Qtrue : Qfalse;
162
+ }
163
+
164
+
165
+ static VALUE method_geometry_prepare(VALUE self)
166
+ {
167
+ RGeo_GeometryData* self_data = RGEO_GEOMETRY_DATA_PTR(self);
168
+ if (self_data->geom) {
169
+ const GEOSPreparedGeometry* prep = self_data->prep;
170
+ if (!prep || prep == (const GEOSPreparedGeometry*)1 || prep == (const GEOSPreparedGeometry*)2) {
171
+ const GEOSPreparedGeometry* prep = GEOSPrepare_r(self_data->geos_context, self_data->geom);
172
+ if (prep) {
173
+ self_data->prep = prep;
174
+ }
175
+ else {
176
+ self_data->prep = (const GEOSPreparedGeometry*)3;
177
+ }
178
+ }
179
+ }
180
+ return self;
181
+ }
182
+
183
+
126
184
  static VALUE method_geometry_dimension(VALUE self)
127
185
  {
128
186
  VALUE result = Qnil;
@@ -339,7 +397,14 @@ static VALUE method_geometry_disjoint(VALUE self, VALUE rhs)
339
397
  if (self_geom) {
340
398
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
341
399
  if (rhs_geom) {
342
- char val = GEOSDisjoint_r(self_data->geos_context, self_geom, rhs_geom);
400
+ char val;
401
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED2
402
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
403
+ if (prep)
404
+ val = GEOSPreparedDisjoint_r(self_data->geos_context, prep, rhs_geom);
405
+ else
406
+ #endif
407
+ val = GEOSDisjoint_r(self_data->geos_context, self_geom, rhs_geom);
343
408
  if (val == 0) {
344
409
  result = Qfalse;
345
410
  }
@@ -360,7 +425,14 @@ static VALUE method_geometry_intersects(VALUE self, VALUE rhs)
360
425
  if (self_geom) {
361
426
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
362
427
  if (rhs_geom) {
363
- char val = GEOSIntersects_r(self_data->geos_context, self_geom, rhs_geom);
428
+ char val;
429
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED1
430
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
431
+ if (prep)
432
+ val = GEOSPreparedIntersects_r(self_data->geos_context, prep, rhs_geom);
433
+ else
434
+ #endif
435
+ val = GEOSIntersects_r(self_data->geos_context, self_geom, rhs_geom);
364
436
  if (val == 0) {
365
437
  result = Qfalse;
366
438
  }
@@ -381,7 +453,14 @@ static VALUE method_geometry_touches(VALUE self, VALUE rhs)
381
453
  if (self_geom) {
382
454
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
383
455
  if (rhs_geom) {
384
- char val = GEOSTouches_r(self_data->geos_context, self_geom, rhs_geom);
456
+ char val;
457
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED2
458
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
459
+ if (prep)
460
+ val = GEOSPreparedTouches_r(self_data->geos_context, prep, rhs_geom);
461
+ else
462
+ #endif
463
+ val = GEOSTouches_r(self_data->geos_context, self_geom, rhs_geom);
385
464
  if (val == 0) {
386
465
  result = Qfalse;
387
466
  }
@@ -402,7 +481,14 @@ static VALUE method_geometry_crosses(VALUE self, VALUE rhs)
402
481
  if (self_geom) {
403
482
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
404
483
  if (rhs_geom) {
405
- char val = GEOSCrosses_r(self_data->geos_context, self_geom, rhs_geom);
484
+ char val;
485
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED2
486
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
487
+ if (prep)
488
+ val = GEOSPreparedCrosses_r(self_data->geos_context, prep, rhs_geom);
489
+ else
490
+ #endif
491
+ val = GEOSCrosses_r(self_data->geos_context, self_geom, rhs_geom);
406
492
  if (val == 0) {
407
493
  result = Qfalse;
408
494
  }
@@ -423,7 +509,14 @@ static VALUE method_geometry_within(VALUE self, VALUE rhs)
423
509
  if (self_geom) {
424
510
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
425
511
  if (rhs_geom) {
426
- char val = GEOSWithin_r(self_data->geos_context, self_geom, rhs_geom);
512
+ char val;
513
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED2
514
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
515
+ if (prep)
516
+ val = GEOSPreparedWithin_r(self_data->geos_context, prep, rhs_geom);
517
+ else
518
+ #endif
519
+ val = GEOSWithin_r(self_data->geos_context, self_geom, rhs_geom);
427
520
  if (val == 0) {
428
521
  result = Qfalse;
429
522
  }
@@ -444,7 +537,14 @@ static VALUE method_geometry_contains(VALUE self, VALUE rhs)
444
537
  if (self_geom) {
445
538
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
446
539
  if (rhs_geom) {
447
- char val = GEOSContains_r(self_data->geos_context, self_geom, rhs_geom);
540
+ char val;
541
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED1
542
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
543
+ if (prep)
544
+ val = GEOSPreparedContains_r(self_data->geos_context, prep, rhs_geom);
545
+ else
546
+ #endif
547
+ val = GEOSContains_r(self_data->geos_context, self_geom, rhs_geom);
448
548
  if (val == 0) {
449
549
  result = Qfalse;
450
550
  }
@@ -465,7 +565,14 @@ static VALUE method_geometry_overlaps(VALUE self, VALUE rhs)
465
565
  if (self_geom) {
466
566
  const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil);
467
567
  if (rhs_geom) {
468
- char val = GEOSOverlaps_r(self_data->geos_context, self_geom, rhs_geom);
568
+ char val;
569
+ #ifdef RGEO_GEOS_SUPPORTS_PREPARED2
570
+ const GEOSPreparedGeometry* prep = rgeo_request_prepared_geometry(self_data);
571
+ if (prep)
572
+ val = GEOSPreparedOverlaps_r(self_data->geos_context, prep, rhs_geom);
573
+ else
574
+ #endif
575
+ val = GEOSOverlaps_r(self_data->geos_context, self_geom, rhs_geom);
469
576
  if (val == 0) {
470
577
  result = Qfalse;
471
578
  }
@@ -617,14 +724,18 @@ static VALUE method_geometry_initialize_copy(VALUE self, VALUE orig)
617
724
  {
618
725
  // Clear out any existing value
619
726
  RGeo_GeometryData* self_data = RGEO_GEOMETRY_DATA_PTR(self);
620
- GEOSGeometry* self_geom = self_data->geom;
621
- if (self_geom) {
622
- GEOSGeom_destroy_r(self_data->geos_context, self_geom);
727
+ if (self_data->geom) {
728
+ GEOSGeom_destroy_r(self_data->geos_context, self_data->geom);
623
729
  self_data->geom = NULL;
624
- self_data->geos_context = NULL;
625
- self_data->factory = Qnil;
626
- self_data->klasses = Qnil;
627
730
  }
731
+ const GEOSPreparedGeometry* prep = self_data->prep;
732
+ if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
733
+ GEOSPreparedGeom_destroy_r(self_data->geos_context, prep);
734
+ }
735
+ self_data->prep = NULL;
736
+ self_data->geos_context = NULL;
737
+ self_data->factory = Qnil;
738
+ self_data->klasses = Qnil;
628
739
 
629
740
  // Copy value from orig
630
741
  const GEOSGeometry* geom = rgeo_get_geos_geometry_safe(orig);
@@ -633,9 +744,12 @@ static VALUE method_geometry_initialize_copy(VALUE self, VALUE orig)
633
744
  GEOSContextHandle_t orig_context = orig_data->geos_context;
634
745
  GEOSGeometry* clone_geom = GEOSGeom_clone_r(orig_context, geom);
635
746
  if (clone_geom) {
747
+ RGeo_FactoryData* factory_data = RGEO_FACTORY_DATA_PTR(orig_data->factory);
636
748
  GEOSSetSRID_r(orig_context, clone_geom, GEOSGetSRID_r(orig_context, geom));
637
749
  self_data->geom = clone_geom;
638
750
  self_data->geos_context = orig_context;
751
+ self_data->prep = factory_data && (factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC != 0) ?
752
+ (GEOSPreparedGeometry*)1 : NULL;
639
753
  self_data->factory = orig_data->factory;
640
754
  self_data->klasses = orig_data->klasses;
641
755
  }
@@ -660,6 +774,8 @@ void rgeo_init_geos_geometry(RGeo_Globals* globals)
660
774
  rb_define_method(geos_geometry_class, "initialize_copy", method_geometry_initialize_copy, 1);
661
775
  rb_define_method(geos_geometry_class, "initialized?", method_geometry_initialized_p, 0);
662
776
  rb_define_method(geos_geometry_class, "factory", method_geometry_factory, 0);
777
+ rb_define_method(geos_geometry_class, "prepared?", method_geometry_prepared_p, 0);
778
+ rb_define_method(geos_geometry_class, "prepare!", method_geometry_prepare, 0);
663
779
  rb_define_method(geos_geometry_class, "dimension", method_geometry_dimension, 0);
664
780
  rb_define_method(geos_geometry_class, "geometry_type", method_geometry_geometry_type, 0);
665
781
  rb_define_method(geos_geometry_class, "srid", method_geometry_srid, 0);
@@ -41,6 +41,13 @@
41
41
  #endif
42
42
  #endif
43
43
 
44
+ #ifdef HAVE_GEOSPREPAREDCONTAINS_R
45
+ #define RGEO_GEOS_SUPPORTS_PREPARED1
46
+ #endif
47
+ #ifdef HAVE_GEOSPREPAREDDISJOINT_R
48
+ #define RGEO_GEOS_SUPPORTS_PREPARED2
49
+ #endif
50
+
44
51
  #ifdef __cplusplus
45
52
  #define RGEO_BEGIN_C extern "C" {
46
53
  #define RGEO_END_C }
@@ -51,6 +51,7 @@ else
51
51
  '/opt/proj/include',
52
52
  '/opt/proj4/include',
53
53
  '/opt/include',
54
+ '/Library/Frameworks/PROJ.framework/unix/include',
54
55
  ::Config::CONFIG['includedir'],
55
56
  '/usr/include',
56
57
  ]
@@ -63,6 +64,7 @@ else
63
64
  '/opt/proj/lib',
64
65
  '/opt/proj4/lib',
65
66
  '/opt/lib',
67
+ '/Library/Frameworks/PROJ.framework/unix/lib',
66
68
  ::Config::CONFIG['libdir'],
67
69
  '/usr/lib',
68
70
  ]
@@ -120,7 +120,14 @@ static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
120
120
 
121
121
  // Copy value from orig
122
122
  RGeo_Proj4Data* orig_data = RGEO_PROJ4_DATA_PTR(orig);
123
- self_data->pj = orig_data->pj;
123
+ if (!NIL_P(orig_data->original_str)) {
124
+ self_data->pj = pj_init_plus(RSTRING_PTR(orig_data->original_str));
125
+ }
126
+ else {
127
+ char* str = pj_get_def(orig_data->pj, 0);
128
+ self_data->pj = pj_init_plus(str);
129
+ pj_dalloc(str);
130
+ }
124
131
  self_data->original_str = orig_data->original_str;
125
132
  self_data->uses_radians = orig_data->uses_radians;
126
133
 
@@ -128,6 +135,28 @@ static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
128
135
  }
129
136
 
130
137
 
138
+ static VALUE method_proj4_set_value(VALUE self, VALUE str, VALUE uses_radians)
139
+ {
140
+ Check_Type(str, T_STRING);
141
+
142
+ // Clear out any existing value
143
+ RGeo_Proj4Data* self_data = RGEO_PROJ4_DATA_PTR(self);
144
+ projPJ pj = self_data->pj;
145
+ if (pj) {
146
+ pj_free(pj);
147
+ self_data->pj = NULL;
148
+ self_data->original_str = Qnil;
149
+ }
150
+
151
+ // Set new data
152
+ self_data->pj = pj_init_plus(RSTRING_PTR(str));
153
+ self_data->original_str = str;
154
+ self_data->uses_radians = RTEST(uses_radians) ? 1 : 0;
155
+
156
+ return self;
157
+ }
158
+
159
+
131
160
  static VALUE method_proj4_get_geographic(VALUE self)
132
161
  {
133
162
  VALUE result = Qnil;
@@ -244,8 +273,11 @@ static void rgeo_init_proj4()
244
273
  VALUE rgeo_module = rb_define_module("RGeo");
245
274
  VALUE coordsys_module = rb_define_module_under(rgeo_module, "CoordSys");
246
275
  VALUE proj4_class = rb_define_class_under(coordsys_module, "Proj4", rb_cObject);
276
+
277
+ rb_define_alloc_func(proj4_class, alloc_proj4);
247
278
  rb_define_module_function(proj4_class, "_create", cmethod_proj4_create, 2);
248
279
  rb_define_method(proj4_class, "initialize_copy", method_proj4_initialize_copy, 1);
280
+ rb_define_method(proj4_class, "_set_value", method_proj4_set_value, 2);
249
281
  rb_define_method(proj4_class, "_original_str", method_proj4_original_str, 0);
250
282
  rb_define_method(proj4_class, "_canonical_str", method_proj4_canonical_str, 0);
251
283
  rb_define_method(proj4_class, "_valid?", method_proj4_is_valid, 0);
@@ -113,6 +113,7 @@ end
113
113
 
114
114
 
115
115
  # Core modules
116
+ require 'rgeo/yaml'
116
117
  require 'rgeo/version'
117
118
  require 'rgeo/error'
118
119
  require 'rgeo/feature'
@@ -242,7 +242,9 @@ module RGeo
242
242
  if @min_x == @max_x || @min_y == @max_y
243
243
  @factory.line(point_min_, point_max_)
244
244
  else
245
- @factory.polygon(@factory.linear_ring(point_min_, @factory.point(@max_x, @min_y, *extras_), point_max_, @factory.point(@min_x, @max_y, *extras_), point_min_))
245
+ @factory.polygon(@factory.linear_ring([point_min_,
246
+ @factory.point(@max_x, @min_y, *extras_), point_max_,
247
+ @factory.point(@min_x, @max_y, *extras_), point_min_]))
246
248
  end
247
249
  end
248
250
  else
@@ -256,10 +258,10 @@ module RGeo
256
258
  #
257
259
  # Supports these options:
258
260
  #
259
- # <tt>:ignore_z</tt>
261
+ # [<tt>:ignore_z</tt>]
260
262
  # Ignore the Z coordinate when testing, even if both objects
261
263
  # have Z. Default is false.
262
- # <tt>:ignore_m</tt>
264
+ # [<tt>:ignore_m</tt>]
263
265
  # Ignore the M coordinate when testing, even if both objects
264
266
  # have M. Default is false.
265
267
 
@@ -116,6 +116,95 @@ module RGeo
116
116
  alias_method :==, :eql?
117
117
 
118
118
 
119
+ # Marshal support
120
+
121
+ def marshal_dump # :nodoc:
122
+ hash_ = {
123
+ 'hasz' => @has_z,
124
+ 'hasm' => @has_m,
125
+ 'srid' => @srid,
126
+ 'wktg' => @wkt_generator._properties,
127
+ 'wkbg' => @wkb_generator._properties,
128
+ 'wktp' => @wkt_parser._properties,
129
+ 'wkbp' => @wkb_parser._properties,
130
+ }
131
+ hash_['proj4'] = @proj4.marshal_dump if @proj4
132
+ hash_['cs'] = @coord_sys.to_wkt if @coord_sys
133
+ hash_
134
+ end
135
+
136
+ def marshal_load(data_) # :nodoc:
137
+ if CoordSys::Proj4.supported? && (proj4_data_ = data_['proj4'])
138
+ proj4_ = CoordSys::Proj4.allocate
139
+ proj4_.marshal_load(proj4_data_)
140
+ else
141
+ proj4_ = nil
142
+ end
143
+ if (coord_sys_data_ = data_['cs'])
144
+ coord_sys_ = CoordSys::CS.create_from_wkt(coord_sys_data_)
145
+ else
146
+ coord_sys_ = nil
147
+ end
148
+ initialize({
149
+ :has_z_coordinate => data_['hasz'],
150
+ :has_m_coordinate => data_['hasm'],
151
+ :srid => data_['srid'],
152
+ :wkt_generator => data_['wktg'],
153
+ :wkb_generator => data_['wkbg'],
154
+ :wkt_parser => data_['wktp'],
155
+ :wkb_parser => data_['wkbp'],
156
+ :proj4 => proj4_,
157
+ :coord_sys => coord_sys_,
158
+ })
159
+ end
160
+
161
+
162
+ # Psych support
163
+
164
+ def init_with(coder_) # :nodoc:
165
+ if (proj4_data_ = coder_['proj4'])
166
+ if proj4_data_.is_a?(::Hash)
167
+ proj4_ = CoordSys::Proj4.create(proj4_data_['proj4'], :radians => proj4_data_['radians'])
168
+ else
169
+ proj4_ = CoordSys::Proj4.create(proj4_data_.to_s)
170
+ end
171
+ else
172
+ proj4_ = nil
173
+ end
174
+ if (coord_sys_data_ = data_['cs'])
175
+ coord_sys_ = CoordSys::CS.create_from_wkt(coord_sys_data_.to_s)
176
+ else
177
+ coord_sys_ = nil
178
+ end
179
+ initialize({
180
+ :has_z_coordinate => data_['has_z_coordinate'],
181
+ :has_m_coordinate => data_['has_m_coordinate'],
182
+ :srid => data_['srid'],
183
+ :wkt_generator => data_['wkt_generator'],
184
+ :wkb_generator => data_['wkb_generator'],
185
+ :wkt_parser => data_['wkt_parser'],
186
+ :wkb_parser => data_['wkb_parser'],
187
+ :proj4 => proj4_,
188
+ :coord_sys => coord_sys_,
189
+ })
190
+ end
191
+
192
+ def encode_with(coder_) # :nodoc:
193
+ coder_['has_z_coordinate'] = @has_z
194
+ coder_['has_m_coordinate'] = @has_m
195
+ coder_['srid'] = @srid
196
+ coder_['wkt_generator'] = @wkt_generator._properties
197
+ coder_['wkb_generator'] = @wkb_generator._properties
198
+ coder_['wkt_parser'] = @wkt_parser._properties
199
+ coder_['wkb_parser'] = @wkb_parser._properties
200
+ if @proj4
201
+ str_ = @proj4.original_str || @proj4.canonical_str
202
+ coder_['proj4'] = @proj4.radians? ? {'proj4' => str_, 'radians' => true} : str_
203
+ end
204
+ coder_['coord_sys'] = @coord_sys.to_wkt if @coord_sys
205
+ end
206
+
207
+
119
208
  # Returns the SRID.
120
209
 
121
210
  def srid
@@ -222,6 +222,43 @@ module RGeo
222
222
  end
223
223
 
224
224
 
225
+ # Marshal support
226
+
227
+ def marshal_dump # :nodoc:
228
+ to_wkt
229
+ end
230
+
231
+ def marshal_load(data_) # :nodoc:
232
+ data_ = data_['wkt'] if data_.is_a?(::Hash)
233
+ temp_ = CS.create_from_wkt(data_)
234
+ if temp_.class == self.class
235
+ temp_.instance_variables.each do |iv_|
236
+ instance_variable_set(iv_, temp_.instance_variable_get(iv_))
237
+ end
238
+ else
239
+ raise ::TypeError, 'Bad Marshal data'
240
+ end
241
+ end
242
+
243
+
244
+ # Psych support
245
+
246
+ def init_with(coder_) # :nodoc:
247
+ temp_ = CS.create_from_wkt(coder_.type == :scalar ? coder_.scalar : coder_['wkt'] )
248
+ if temp_.class == self.class
249
+ temp_.instance_variables.each do |iv_|
250
+ instance_variable_set(iv_, temp_.instance_variable_get(iv_))
251
+ end
252
+ else
253
+ raise ::TypeError, 'Bad YAML data'
254
+ end
255
+ end
256
+
257
+ def encode_with(coder_) # :nodoc:
258
+ coder_['wkt'] = to_wkt
259
+ end
260
+
261
+
225
262
  class << self
226
263
 
227
264
  private :new
@@ -83,6 +83,33 @@ module RGeo
83
83
  alias_method :==, :eql?
84
84
 
85
85
 
86
+ # Marshal support
87
+
88
+ def marshal_dump # :nodoc:
89
+ {'rad' => radians?, 'str' => original_str || canonical_str}
90
+ end
91
+
92
+ def marshal_load(data_) # :nodoc:
93
+ _set_value(data_['str'], data_['rad'])
94
+ end
95
+
96
+
97
+ # Psych support
98
+
99
+ def init_with(coder_) # :nodoc:
100
+ if coder_.type == :scalar
101
+ _set_value(coder_.scalar, false)
102
+ else
103
+ _set_value(coder_['proj4'], coder_['radians'])
104
+ end
105
+ end
106
+
107
+ def encode_with(coder_) # :nodoc:
108
+ coder_['proj4'] = original_str || canonical_str
109
+ coder_['radians'] = radians?
110
+ end
111
+
112
+
86
113
  # Returns the "canonical" string definition for this coordinate
87
114
  # system, as reported by Proj4. This may be slightly different
88
115
  # from the definition used to construct this object.
@@ -202,6 +229,19 @@ module RGeo
202
229
  # Create a new Proj4 object, given a definition, which may be
203
230
  # either a string or a hash. Raises Error::UnsupportedOperation
204
231
  # if the given definition is invalid or Proj4 is not supported.
232
+ #
233
+ # Recognized options include:
234
+ #
235
+ # [<tt>:radians</tt>]
236
+ # If set to true, then this proj4 will represent geographic
237
+ # (latitude/longitude) coordinates in radians rather than
238
+ # degrees. If this is a geographic coordinate system, then its
239
+ # units will be in radians. If this is a projected coordinate
240
+ # system, then its units will be unchanged, but any geographic
241
+ # coordinate system obtained using get_geographic will use
242
+ # radians as its units. If this is a geocentric or other type of
243
+ # coordinate system, this has no effect. Default is false.
244
+ # (That is all coordinates are in degrees by default.)
205
245
 
206
246
  def new(defn_, opts_={})
207
247
  result_ = create(defn_, opts_)
@@ -67,6 +67,7 @@ module RGeo
67
67
  if flags_ & 6 == 6
68
68
  raise Error::UnsupportedOperation, "GEOS cannot support both Z and M coordinates at the same time."
69
69
  end
70
+ flags_ |= 8 unless opts_[:auto_prepare] == :disabled
70
71
 
71
72
  # Buffer resolution
72
73
  buffer_resolution_ = opts_[:buffer_resolution].to_i
@@ -206,6 +207,8 @@ module RGeo
206
207
  _flags & 0x1 != 0
207
208
  when :buffer_resolution
208
209
  _buffer_resolution
210
+ when :auto_prepare
211
+ _flags & 0x8 != 0 ? :simple : :disabled
209
212
  else
210
213
  nil
211
214
  end
@@ -64,7 +64,7 @@ module RGeo
64
64
 
65
65
 
66
66
  # Returns true if the given feature is a CAPI GEOS feature, or if
67
- # the given factory is a native GEOS factory.
67
+ # the given factory is a CAPI GEOS factory.
68
68
 
69
69
  def is_capi_geos?(object_)
70
70
  Factory === object_ || GeometryImpl === object_ ||
@@ -84,7 +84,7 @@ module RGeo
84
84
 
85
85
 
86
86
  # Returns true if the given feature is a GEOS feature, or if the given
87
- # factory is a GEOS factory.
87
+ # factory is a GEOS factory. Does not distinguish between CAPI and FFI.
88
88
 
89
89
  def is_geos?(object_)
90
90
  Factory === object_ || GeometryImpl === object_ ||
@@ -188,6 +188,15 @@ module RGeo
188
188
  # default configuration for WKRep::WKBGenerator.
189
189
  # Note that the special <tt>:geos</tt> value is not supported for
190
190
  # ZM factories, since GEOS currently can't handle ZM natively.
191
+ # [<tt>:auto_prepare</tt>]
192
+ # Request an auto-prepare strategy. Supported values are
193
+ # <tt>:simple</tt> and <tt>:disabled</tt>. The former (which is
194
+ # the default) generates a prepared geometry the second time an
195
+ # operation that would benefit from it is called. The latter
196
+ # never automatically generates a prepared geometry (unless you
197
+ # generate on explicitly using the <tt>prepare!</tt> method).
198
+ # Currently, prepared geometries are supported under CAPI but
199
+ # not FFI.
191
200
 
192
201
  def factory(opts_={})
193
202
  if supported?
@@ -123,6 +123,16 @@ module RGeo
123
123
  end
124
124
 
125
125
 
126
+ def _properties # :nodoc:
127
+ {
128
+ :type_format => @type_format,
129
+ :emit_ewkb_srid => @emit_ewkb_srid,
130
+ :hex_format => @hex_format,
131
+ :little_endian => @little_endian,
132
+ }
133
+ end
134
+
135
+
126
136
  # Generate and return the WKB format for the given geometry object,
127
137
  # according to the current settings.
128
138
 
@@ -127,10 +127,14 @@ module RGeo
127
127
  @ignore_extra_bytes
128
128
  end
129
129
 
130
- # Returns true if this parser can auto-detect hex.
131
- # See WKBParser for details.
132
- def auto_detect_hex?
133
- @auto_detect_hex
130
+
131
+ def _properties # :nodoc:
132
+ {
133
+ :support_ewkb => @support_ewkb,
134
+ :support_wkb12 => @support_wkb12,
135
+ :ignore_extra_bytes => @ignore_extra_bytes,
136
+ :default_srid => @default_srid,
137
+ }
134
138
  end
135
139
 
136
140
 
@@ -114,6 +114,16 @@ module RGeo
114
114
  end
115
115
 
116
116
 
117
+ def _properties # :nodoc:
118
+ {
119
+ :tag_format => @tag_format,
120
+ :emit_ewkt_srid => @emit_ewkt_srid,
121
+ :square_brackets => @square_brackets,
122
+ :convert_case => @convert_case,
123
+ }
124
+ end
125
+
126
+
117
127
  # Generate and return the WKT format for the given geometry object,
118
128
  # according to the current settings.
119
129
 
@@ -141,6 +151,7 @@ module RGeo
141
151
 
142
152
  def _generate_feature(obj_, toplevel_=false) # :nodoc:
143
153
  type_ = obj_.geometry_type
154
+ type_ = Feature::LineString if type_.subtype_of?(Feature::LineString)
144
155
  tag_ = type_.type_name
145
156
  if @tag_format == :ewkt
146
157
  if @cur_support_m && !@cur_support_z
@@ -162,7 +173,7 @@ module RGeo
162
173
  end
163
174
  if type_ == Feature::Point
164
175
  "#{tag_} #{_generate_point(obj_)}"
165
- elsif type_.subtype_of?(Feature::LineString)
176
+ elsif type_ == Feature::LineString
166
177
  "#{tag_} #{_generate_line_string(obj_)}"
167
178
  elsif type_ == Feature::Polygon
168
179
  "#{tag_} #{_generate_polygon(obj_)}"
@@ -142,6 +142,17 @@ module RGeo
142
142
  end
143
143
 
144
144
 
145
+ def _properties # :nodoc:
146
+ {
147
+ :support_ewkt => @support_ewkt,
148
+ :support_wkt12 => @support_wkt12,
149
+ :strict_wkt11 => @strict_wkt11,
150
+ :ignore_extra_tokens => @ignore_extra_tokens,
151
+ :default_srid => @default_srid,
152
+ }
153
+ end
154
+
155
+
145
156
  # Parse the given string, and return a geometry object.
146
157
 
147
158
  def parse(str_)
@@ -0,0 +1,59 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # RGeo yaml support
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ begin
38
+ require 'psych'
39
+ rescue ::LoadError
40
+ end
41
+
42
+
43
+ module RGeo
44
+
45
+
46
+ # :stopdoc:
47
+ PSYCH_AVAILABLE = defined?(::Psych)
48
+ # :startdoc:
49
+
50
+
51
+ # Returns true if YAML serialization and deserialization is supported.
52
+ # YAML support requires the Psych library/gem.
53
+
54
+ def self.yaml_supported?
55
+ PSYCH_AVAILABLE
56
+ end
57
+
58
+
59
+ end
@@ -360,6 +360,34 @@ module RGeo
360
360
  end
361
361
 
362
362
 
363
+ def test_marshal_roundtrip
364
+ input_ = 'COMPD_CS["OSGB36 / British National Grid + ODN",PROJCS["OSGB 1936 / British National Grid",GEOGCS["OSGB 1936",DATUM["OSGB 1936",SPHEROID["Airy 1830",6377563.396,299.3249646,AUTHORITY["EPSG","7001"]],TOWGS84[446.448,-125.157,542.06,0.15,0.247,0.842,-4.2261596151967575],AUTHORITY["EPSG","6277"]],PRIMEM["Greenwich",0.0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943295],AXIS["Geodetic latitude",NORTH],AXIS["Geodetic longitude",EAST],AUTHORITY["EPSG","4277"]],PROJECTION["Transverse Mercator",AUTHORITY["EPSG","9807"]],PARAMETER["central_meridian",-2.0],PARAMETER["latitude_of_origin",49.0],PARAMETER["scale_factor",0.9996012717],PARAMETER["false_easting",400000.0],PARAMETER["false_northing",-100000.0],UNIT["m",1.0],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","27700"]],VERT_CS["Newlyn",VERT_DATUM["Ordnance Datum Newlyn",2005,AUTHORITY["EPSG","5101"]],UNIT["m",1.0],AXIS["Gravity-related height",UP],AUTHORITY["EPSG","5701"]],AUTHORITY["EPSG","7405"]]'
365
+ obj1_ = ::RGeo::CoordSys::CS.create_from_wkt(input_)
366
+ dump_ = ::Marshal.dump(obj1_)
367
+ obj2_ = ::Marshal.load(dump_)
368
+ assert_equal(obj1_, obj2_)
369
+ end
370
+
371
+
372
+ if ::RGeo.yaml_supported?
373
+
374
+
375
+ def test_yaml_roundtrip
376
+ input_ = 'COMPD_CS["OSGB36 / British National Grid + ODN",PROJCS["OSGB 1936 / British National Grid",GEOGCS["OSGB 1936",DATUM["OSGB 1936",SPHEROID["Airy 1830",6377563.396,299.3249646,AUTHORITY["EPSG","7001"]],TOWGS84[446.448,-125.157,542.06,0.15,0.247,0.842,-4.2261596151967575],AUTHORITY["EPSG","6277"]],PRIMEM["Greenwich",0.0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943295],AXIS["Geodetic latitude",NORTH],AXIS["Geodetic longitude",EAST],AUTHORITY["EPSG","4277"]],PROJECTION["Transverse Mercator",AUTHORITY["EPSG","9807"]],PARAMETER["central_meridian",-2.0],PARAMETER["latitude_of_origin",49.0],PARAMETER["scale_factor",0.9996012717],PARAMETER["false_easting",400000.0],PARAMETER["false_northing",-100000.0],UNIT["m",1.0],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","27700"]],VERT_CS["Newlyn",VERT_DATUM["Ordnance Datum Newlyn",2005,AUTHORITY["EPSG","5101"]],UNIT["m",1.0],AXIS["Gravity-related height",UP],AUTHORITY["EPSG","5701"]],AUTHORITY["EPSG","7405"]]'
377
+ obj1_ = ::RGeo::CoordSys::CS.create_from_wkt(input_)
378
+ dump_ = ::Psych.dump(obj1_)
379
+ obj2_ = ::Psych.load(dump_)
380
+ assert_equal(obj1_, obj2_)
381
+ end
382
+
383
+
384
+ else
385
+
386
+ puts "WARNING: Psych not installed. Skipping YAML tests."
387
+
388
+ end
389
+
390
+
363
391
  end
364
392
 
365
393
  end
@@ -46,7 +46,7 @@ module RGeo
46
46
 
47
47
 
48
48
  def test_create_wgs84
49
- proj_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
49
+ proj_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
50
50
  assert_equal(true, proj_.geographic?)
51
51
  assert_equal('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', proj_.original_str)
52
52
  assert_equal(' +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0', proj_.canonical_str)
@@ -54,19 +54,19 @@ module RGeo
54
54
 
55
55
 
56
56
  def test_get_wgs84_geographic
57
- proj_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
57
+ proj_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
58
58
  proj2_ = proj_.get_geographic
59
59
  assert_nil(proj2_.original_str)
60
60
  assert_equal(true, proj2_.geographic?)
61
- coords_ = RGeo::CoordSys::Proj4.transform_coords(proj_, proj2_, 1, 2, 0)
61
+ coords_ = ::RGeo::CoordSys::Proj4.transform_coords(proj_, proj2_, 1, 2, 0)
62
62
  assert_equal([1, 2, 0], coords_)
63
63
  end
64
64
 
65
65
 
66
66
  def test_identity_transform
67
- proj_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
68
- assert_equal([1, 2, 0], RGeo::CoordSys::Proj4.transform_coords(proj_, proj_, 1, 2, 0))
69
- assert_equal([1, 2], RGeo::CoordSys::Proj4.transform_coords(proj_, proj_, 1, 2, nil))
67
+ proj_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
68
+ assert_equal([1, 2, 0], ::RGeo::CoordSys::Proj4.transform_coords(proj_, proj_, 1, 2, 0))
69
+ assert_equal([1, 2], ::RGeo::CoordSys::Proj4.transform_coords(proj_, proj_, 1, 2, nil))
70
70
  end
71
71
 
72
72
 
@@ -92,45 +92,100 @@ module RGeo
92
92
 
93
93
 
94
94
  def test_simple_mercator_transform
95
- geography_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :radians => true)
96
- projection_ = RGeo::CoordSys::Proj4.create('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs')
97
- _assert_xy_close(_project_merc(0, 0), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 0, 0, nil))
98
- _assert_xy_close(_project_merc(0.01, 0.01), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 0.01, 0.01, nil))
99
- _assert_xy_close(_project_merc(1, 1), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 1, 1, nil))
100
- _assert_xy_close(_project_merc(-1, -1), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, -1, -1, nil))
101
- _assert_xy_close(_unproject_merc(0, 0), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 0, 0, nil))
102
- _assert_xy_close(_unproject_merc(10000, 10000), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 10000, 10000, nil))
103
- _assert_xy_close(_unproject_merc(-20000000, -20000000), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, -20000000, -20000000, nil))
95
+ geography_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :radians => true)
96
+ projection_ = ::RGeo::CoordSys::Proj4.create('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs')
97
+ _assert_xy_close(_project_merc(0, 0), ::RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 0, 0, nil))
98
+ _assert_xy_close(_project_merc(0.01, 0.01), ::RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 0.01, 0.01, nil))
99
+ _assert_xy_close(_project_merc(1, 1), ::RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 1, 1, nil))
100
+ _assert_xy_close(_project_merc(-1, -1), ::RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, -1, -1, nil))
101
+ _assert_xy_close(_unproject_merc(0, 0), ::RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 0, 0, nil))
102
+ _assert_xy_close(_unproject_merc(10000, 10000), ::RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 10000, 10000, nil))
103
+ _assert_xy_close(_unproject_merc(-20000000, -20000000), ::RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, -20000000, -20000000, nil))
104
104
  end
105
105
 
106
106
 
107
107
  def test_equivalence
108
- proj1_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
109
- proj2_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
108
+ proj1_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
109
+ proj2_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
110
110
  assert_equal(proj1_, proj2_)
111
111
  end
112
112
 
113
113
 
114
114
  def test_point_projection_cast
115
- geography_ = RGeo::Geos.factory(:proj4 => '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :srid =>4326)
116
- projection_ = RGeo::Geos.factory(:proj4 => '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs', :srid => 27700)
115
+ geography_ = ::RGeo::Geos.factory(:proj4 => '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :srid =>4326)
116
+ projection_ = ::RGeo::Geos.factory(:proj4 => '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs', :srid => 27700)
117
117
  proj_point_ = projection_.parse_wkt('POINT(473600.5000000000000000 186659.7999999999883585)')
118
- geo_point_ = RGeo::Feature.cast(proj_point_, :project => true, :factory => geography_)
118
+ geo_point_ = ::RGeo::Feature.cast(proj_point_, :project => true, :factory => geography_)
119
119
  _assert_close_enough(-0.9393598527244420, geo_point_.x)
120
120
  _assert_close_enough(51.5740106527552697, geo_point_.y)
121
121
  end
122
122
 
123
123
 
124
124
  def test_point_transform_lowlevel
125
- geography_ = RGeo::Geos.factory(:proj4 => '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :srid =>4326)
126
- projection_ = RGeo::Geos.factory(:proj4 => '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs', :srid => 27700)
125
+ geography_ = ::RGeo::Geos.factory(:proj4 => '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :srid =>4326)
126
+ projection_ = ::RGeo::Geos.factory(:proj4 => '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs', :srid => 27700)
127
127
  proj_point_ = projection_.parse_wkt('POINT(473600.5000000000000000 186659.7999999999883585)')
128
- geo_point_ = RGeo::CoordSys::Proj4.transform(projection_.proj4, proj_point_, geography_.proj4, geography_)
128
+ geo_point_ = ::RGeo::CoordSys::Proj4.transform(projection_.proj4, proj_point_, geography_.proj4, geography_)
129
129
  _assert_close_enough(-0.9393598527244420, geo_point_.x)
130
130
  _assert_close_enough(51.5740106527552697, geo_point_.y)
131
131
  end
132
132
 
133
133
 
134
+ def test_geocentric
135
+ obj1_ = ::RGeo::CoordSys::Proj4.create('+proj=geocent +ellps=WGS84')
136
+ assert_equal(true, obj1_.geocentric?)
137
+ end
138
+
139
+
140
+ def test_get_geographic
141
+ projection_ = ::RGeo::CoordSys::Proj4.create('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs')
142
+ geographic_ = projection_.get_geographic
143
+ expected_ = ::RGeo::CoordSys::Proj4.create('+proj=latlong +a=6378137 +b=6378137 +nadgrids=@null')
144
+ assert_equal(expected_, geographic_)
145
+ end
146
+
147
+
148
+ def test_marshal_roundtrip
149
+ obj1_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
150
+ dump_ = ::Marshal.dump(obj1_)
151
+ obj2_ = ::Marshal.load(dump_)
152
+ assert_equal(obj1_, obj2_)
153
+ end
154
+
155
+
156
+ def test_dup
157
+ obj1_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
158
+ obj2_ = obj1_.dup
159
+ assert_equal(obj1_, obj2_)
160
+ end
161
+
162
+
163
+ def test_dup_of_get_geographic
164
+ obj1_ = ::RGeo::CoordSys::Proj4.create('+proj=latlong +datum=WGS84 +ellps=WGS84')
165
+ obj2_ = obj1_.get_geographic
166
+ obj3_ = obj2_.dup
167
+ assert_equal(obj1_, obj3_)
168
+ end
169
+
170
+
171
+ if ::RGeo.yaml_supported?
172
+
173
+
174
+ def test_yaml_roundtrip
175
+ obj1_ = ::RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
176
+ dump_ = ::Psych.dump(obj1_)
177
+ obj2_ = ::Psych.load(dump_)
178
+ assert_equal(obj1_, obj2_)
179
+ end
180
+
181
+
182
+ else
183
+
184
+ puts "WARNING: Psych not installed. Skipping YAML tests."
185
+
186
+ end
187
+
188
+
134
189
  end
135
190
 
136
191
  end
@@ -65,6 +65,39 @@ module RGeo
65
65
  end
66
66
 
67
67
 
68
+ def test_prepare
69
+ p1_ = @factory.point(1, 2)
70
+ p2_ = @factory.point(3, 4)
71
+ p3_ = @factory.point(5, 2)
72
+ polygon_ = @factory.polygon(@factory.linear_ring([p1_, p2_, p3_, p1_]))
73
+ assert_equal(false, polygon_.prepared?)
74
+ polygon_.prepare!
75
+ assert_equal(true, polygon_.prepared?)
76
+ end
77
+
78
+
79
+ def test_auto_prepare
80
+ p1_ = @factory.point(1, 2)
81
+ p2_ = @factory.point(3, 4)
82
+ p3_ = @factory.point(5, 2)
83
+ polygon_ = @factory.polygon(@factory.linear_ring([p1_, p2_, p3_, p1_]))
84
+ assert_equal(false, polygon_.prepared?)
85
+ polygon_.intersects?(p1_)
86
+ assert_equal(false, polygon_.prepared?)
87
+ polygon_.intersects?(p2_)
88
+ assert_equal(true, polygon_.prepared?)
89
+
90
+ factory_no_auto_prepare_ = ::RGeo::Geos.factory(:srid => 4326, :auto_prepare => :disabled)
91
+ polygon2_ = factory_no_auto_prepare_.polygon(
92
+ factory_no_auto_prepare_.linear_ring([p1_, p2_, p3_, p1_]))
93
+ assert_equal(false, polygon2_.prepared?)
94
+ polygon2_.intersects?(p1_)
95
+ assert_equal(false, polygon2_.prepared?)
96
+ polygon2_.intersects?(p2_)
97
+ assert_equal(false, polygon2_.prepared?)
98
+ end
99
+
100
+
68
101
  end
69
102
 
70
103
  end
metadata CHANGED
@@ -1,30 +1,31 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rgeo
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
4
5
  prerelease:
5
- version: 0.3.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Daniel Azuma
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-05-24 00:00:00 Z
12
+ date: 2011-08-12 00:00:00.000000000 Z
14
13
  dependencies: []
15
-
16
- description: RGeo is a geospatial data library for Ruby. It provides an implementation of the Open Geospatial Consortium's Simple Features Specification, used by most standard spatial/geographic data storage systems such as PostGIS. A number of add-on modules are also available to help with writing location-based applications using Ruby-based frameworks such as Ruby On Rails.
14
+ description: RGeo is a geospatial data library for Ruby. It provides an implementation
15
+ of the Open Geospatial Consortium's Simple Features Specification, used by most
16
+ standard spatial/geographic data storage systems such as PostGIS. A number of add-on
17
+ modules are also available to help with writing location-based applications using
18
+ Ruby-based frameworks such as Ruby On Rails.
17
19
  email: dazuma@gmail.com
18
20
  executables: []
19
-
20
- extensions:
21
+ extensions:
21
22
  - ext/geos_c_impl/extconf.rb
22
23
  - ext/proj4_c_impl/extconf.rb
23
- extra_rdoc_files:
24
+ extra_rdoc_files:
24
25
  - History.rdoc
25
26
  - README.rdoc
26
27
  - Spatial_Programming_With_RGeo.rdoc
27
- files:
28
+ files:
28
29
  - lib/rgeo/cartesian/analysis.rb
29
30
  - lib/rgeo/cartesian/bounding_box.rb
30
31
  - lib/rgeo/cartesian/calculations.rb
@@ -95,6 +96,7 @@ files:
95
96
  - lib/rgeo/wkrep/wkt_generator.rb
96
97
  - lib/rgeo/wkrep/wkt_parser.rb
97
98
  - lib/rgeo/wkrep.rb
99
+ - lib/rgeo/yaml.rb
98
100
  - lib/rgeo.rb
99
101
  - ext/geos_c_impl/extconf.rb
100
102
  - ext/proj4_c_impl/extconf.rb
@@ -193,32 +195,29 @@ files:
193
195
  - Version
194
196
  homepage: http://virtuoso.rubyforge.org/rgeo
195
197
  licenses: []
196
-
197
198
  post_install_message:
198
199
  rdoc_options: []
199
-
200
- require_paths:
200
+ require_paths:
201
201
  - lib
202
- required_ruby_version: !ruby/object:Gem::Requirement
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
203
  none: false
204
- requirements:
205
- - - ">="
206
- - !ruby/object:Gem::Version
204
+ requirements:
205
+ - - ! '>='
206
+ - !ruby/object:Gem::Version
207
207
  version: 1.8.7
208
- required_rubygems_version: !ruby/object:Gem::Requirement
208
+ required_rubygems_version: !ruby/object:Gem::Requirement
209
209
  none: false
210
- requirements:
211
- - - ">"
212
- - !ruby/object:Gem::Version
210
+ requirements:
211
+ - - ! '>'
212
+ - !ruby/object:Gem::Version
213
213
  version: 1.3.1
214
214
  requirements: []
215
-
216
215
  rubyforge_project: virtuoso
217
- rubygems_version: 1.8.2
216
+ rubygems_version: 1.8.7
218
217
  signing_key:
219
218
  specification_version: 3
220
219
  summary: RGeo is a geospatial data library for Ruby.
221
- test_files:
220
+ test_files:
222
221
  - test/coord_sys/tc_active_record_table.rb
223
222
  - test/coord_sys/tc_ogc_cs.rb
224
223
  - test/coord_sys/tc_proj4.rb