rgeo 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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