rgeo-proj4 2.0.1 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05e81871744567d55f6b9d11e115954040f5262e9d3317b9792973f1806f655a
4
- data.tar.gz: 0a3f2943bf7c80eb4c9d0680b382ab0c9eed83543ef1f4383326e4bdfb6da250
3
+ metadata.gz: b578b226ebc3b376a92f58cf080d34f237b5929751e6b856e493d9b6a6daa1ae
4
+ data.tar.gz: 84f4953ac2aea3783e7a807542c7aaf102b265dc454a9de97c340d70f04685c1
5
5
  SHA512:
6
- metadata.gz: 74ad26d2f7f983b9415b1b301180fe0352a09d4df7425227c2d012220468e147d9b1787c41de2b13f2db9cb5bf9e8a35038beee362393427911854cbff4c49f8
7
- data.tar.gz: bcd150775bfa449dad65dd8035f9ceb4e23192dac1f258de2c0b3edf58362e6c48a4b7da7c710bcf3b43de61c92ca64b159f7b6eec2cdaa1ca0cda7a1a1a5ff0
6
+ metadata.gz: bb2bddfdc101da5c0a4b2af5d5445ce7e57f8d49505b5bb2f53376e81b5ed392d4d2183c11e6cc1e0d86fc5b2fc83cc1afe1d6a3c72fcf8924d779fbd04fdffb
7
+ data.tar.gz: 3f21328f3beff54191cf496f784a432185f9999d4b71ddeab91d772627f26bbc97deb1882cab9d9f997d16432993d2c742c3d2638005d2f372959428201f4e05
@@ -22,6 +22,7 @@ else
22
22
  "/opt/proj/include",
23
23
  "/opt/proj4/include",
24
24
  "/opt/include",
25
+ "/opt/homebrew/include",
25
26
  "/Library/Frameworks/PROJ.framework/unix/include",
26
27
  "/usr/include"
27
28
  ]
@@ -36,6 +37,7 @@ else
36
37
  "/opt/proj/lib",
37
38
  "/opt/proj4/lib",
38
39
  "/opt/lib",
40
+ "/opt/homebrew/lib",
39
41
  "/Library/Frameworks/PROJ.framework/unix/lib",
40
42
  "/usr/lib",
41
43
  "/usr/lib64"
@@ -45,15 +47,19 @@ else
45
47
 
46
48
  found_proj_ = false
47
49
  header_dirs_, lib_dirs_ = dir_config("proj", header_dirs_, lib_dirs_)
48
- dflag = "-DACCEPT_USE_OF_DEPRECATED_PROJ_API_H"
49
- if have_header("proj_api.h", nil, dflag)
50
+ if have_header("proj.h")
50
51
  $libs << " -lproj"
51
- if have_func("pj_init_plus", "proj_api.h", dflag)
52
+
53
+ if have_func("proj_create", "proj.h")
52
54
  found_proj_ = true
55
+ have_func("proj_create_crs_to_crs_from_pj", "proj.h")
56
+ have_func("proj_normalize_for_visualization", "proj.h")
53
57
  else
54
58
  $libs.gsub!(" -lproj", "")
55
59
  end
56
60
  end
61
+ have_func("rb_gc_mark_movable")
62
+
57
63
  unless found_proj_
58
64
  puts "**** WARNING: Unable to find Proj headers or Proj version is too old."
59
65
  puts "**** Compiling without Proj support."
@@ -1,12 +1,21 @@
1
1
  /*
2
2
  Main initializer for Proj4 wrapper
3
3
  */
4
- #ifdef HAVE_PROJ_API_H
5
- #ifdef HAVE_PJ_INIT_PLUS
6
- #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
4
+ #ifdef HAVE_PROJ_H
5
+ #ifdef HAVE_PROJ_CREATE
6
+ #ifdef HAVE_PROJ_CREATE_CRS_TO_CRS_FROM_PJ
7
+ #ifdef HAVE_PROJ_NORMALIZE_FOR_VISUALIZATION
7
8
  #define RGEO_PROJ4_SUPPORTED
8
9
  #endif
9
10
  #endif
11
+ #endif
12
+ #endif
13
+
14
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
15
+ #define mark rb_gc_mark_movable
16
+ #else
17
+ #define mark rb_gc_mark
18
+ #endif
10
19
 
11
20
  #ifdef __cplusplus
12
21
  #define RGEO_BEGIN_C extern "C" {
@@ -20,7 +29,7 @@
20
29
  #ifdef RGEO_PROJ4_SUPPORTED
21
30
 
22
31
  #include <ruby.h>
23
- #include <proj_api.h>
32
+ #include <proj.h>
24
33
 
25
34
  #endif
26
35
 
@@ -30,78 +39,159 @@ RGEO_BEGIN_C
30
39
 
31
40
  #ifdef RGEO_PROJ4_SUPPORTED
32
41
 
42
+ #if PROJ_VERSION_MAJOR == 6 && PROJ_VERSION_MINOR < 3
43
+ #define WKT_TYPE PJ_WKT2_2018
44
+ #else
45
+ #define WKT_TYPE PJ_WKT2_2019
46
+ #endif
33
47
 
34
48
  typedef struct {
35
- projPJ pj;
49
+ PJ *pj;
36
50
  VALUE original_str;
37
51
  char uses_radians;
38
52
  } RGeo_Proj4Data;
39
53
 
40
-
41
- #define RGEO_PROJ4_DATA_PTR(obj) ((RGeo_Proj4Data*)DATA_PTR(obj))
54
+ typedef struct {
55
+ PJ *crs_to_crs;
56
+ } RGeo_CRSToCRSData;
42
57
 
43
58
 
44
59
  // Destroy function for proj data.
60
+ static void rgeo_proj4_free(void *ptr)
61
+ {
62
+ RGeo_Proj4Data *data = (RGeo_Proj4Data *)ptr;
63
+ if(data->pj){
64
+ proj_destroy(data->pj);
65
+ }
66
+ free(data);
67
+ }
45
68
 
46
- static void destroy_proj4_func(RGeo_Proj4Data* data)
69
+ // Destroy function for crs_to_crs data.
70
+ static void rgeo_crs_to_crs_free(void *ptr)
47
71
  {
48
- if (data->pj) {
49
- pj_free(data->pj);
72
+ RGeo_CRSToCRSData *data = (RGeo_CRSToCRSData *)ptr;
73
+ if(data->crs_to_crs){
74
+ proj_destroy(data->crs_to_crs);
50
75
  }
51
76
  free(data);
52
77
  }
53
78
 
54
79
 
55
- static void mark_proj4_func(RGeo_Proj4Data* data)
80
+ static size_t rgeo_proj4_memsize(const void *ptr)
56
81
  {
57
- if (!NIL_P(data->original_str)) {
58
- rb_gc_mark(data->original_str);
82
+ size_t size = 0;
83
+ const RGeo_Proj4Data *data = (const RGeo_Proj4Data *)ptr;
84
+
85
+ size += sizeof(*data);
86
+ if(data->pj){
87
+ size += sizeof(data->pj);
59
88
  }
89
+ return size;
60
90
  }
61
91
 
92
+ static size_t rgeo_crs_to_crs_memsize(const void *ptr)
93
+ {
94
+ size_t size = 0;
95
+ const RGeo_CRSToCRSData *data = (const RGeo_CRSToCRSData *)ptr;
96
+ size += sizeof(*data);
97
+ if(data->crs_to_crs){
98
+ size += sizeof(data->crs_to_crs);
99
+ }
100
+ return size;
101
+ }
102
+
103
+ static void rgeo_proj4_mark(void *ptr)
104
+ {
105
+ RGeo_Proj4Data *data = (RGeo_Proj4Data *)ptr;
106
+ if(!NIL_P(data->original_str)){
107
+ mark(data->original_str);
108
+ }
109
+ }
110
+
111
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
112
+ static void rgeo_proj4_compact(void *ptr)
113
+ {
114
+ RGeo_Proj4Data *data = (RGeo_Proj4Data *)ptr;
115
+ if(data && !NIL_P(data->original_str)){
116
+ data->original_str = rb_gc_location(data->original_str);
117
+ }
118
+ }
119
+ #endif
62
120
 
63
- static VALUE alloc_proj4(VALUE klass)
121
+ static void rgeo_proj4_clear_struct(RGeo_Proj4Data *data)
122
+ {
123
+ if(data->pj){
124
+ proj_destroy(data->pj);
125
+ data->pj = NULL;
126
+ data->original_str = Qnil;
127
+ }
128
+ }
129
+
130
+ static const rb_data_type_t rgeo_proj4_data_type = {
131
+ "RGeo::CoordSys::Proj4",
132
+ {rgeo_proj4_mark, rgeo_proj4_free, rgeo_proj4_memsize,
133
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
134
+ rgeo_proj4_compact
135
+ #endif
136
+ },
137
+ 0, 0,
138
+ RUBY_TYPED_FREE_IMMEDIATELY};
139
+
140
+ static const rb_data_type_t rgeo_crs_to_crs_data_type = {
141
+ "RGeo::CoordSys::CRSToCRS",
142
+ {0, rgeo_crs_to_crs_free, rgeo_crs_to_crs_memsize},
143
+ 0, 0,
144
+ RUBY_TYPED_FREE_IMMEDIATELY};
145
+
146
+ static VALUE rgeo_proj4_data_alloc(VALUE self)
64
147
  {
65
148
  VALUE result;
66
- RGeo_Proj4Data* data;
149
+ RGeo_Proj4Data *data = ALLOC(RGeo_Proj4Data);
67
150
 
68
151
  result = Qnil;
69
- data = ALLOC(RGeo_Proj4Data);
70
- if (data) {
152
+
153
+ if(data){
71
154
  data->pj = NULL;
72
155
  data->original_str = Qnil;
73
156
  data->uses_radians = 0;
74
- result = Data_Wrap_Struct(klass, mark_proj4_func, destroy_proj4_func, data);
157
+ result = TypedData_Wrap_Struct(self, &rgeo_proj4_data_type, data);
75
158
  }
76
159
  return result;
77
160
  }
78
161
 
79
162
 
163
+ static VALUE rgeo_crs_to_crs_data_alloc(VALUE self)
164
+ {
165
+ VALUE result;
166
+ RGeo_CRSToCRSData *data = ALLOC(RGeo_CRSToCRSData);
167
+
168
+ result = Qnil;
169
+
170
+ if(data){
171
+ data->crs_to_crs = NULL;
172
+ result = TypedData_Wrap_Struct(self, &rgeo_crs_to_crs_data_type, data);
173
+ }
174
+ return result;
175
+ }
176
+
80
177
  static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
81
178
  {
82
- RGeo_Proj4Data* self_data;
83
- projPJ pj;
84
- RGeo_Proj4Data* orig_data;
85
- char* str;
179
+ RGeo_Proj4Data *self_data;
180
+ RGeo_Proj4Data *orig_data;
181
+ const char* str;
86
182
 
87
183
  // Clear out any existing value
88
- self_data = RGEO_PROJ4_DATA_PTR(self);
89
- pj = self_data->pj;
90
- if (pj) {
91
- pj_free(pj);
92
- self_data->pj = NULL;
93
- self_data->original_str = Qnil;
94
- }
184
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
185
+ rgeo_proj4_clear_struct(self_data);
95
186
 
96
187
  // Copy value from orig
97
- orig_data = RGEO_PROJ4_DATA_PTR(orig);
188
+ TypedData_Get_Struct(orig, RGeo_Proj4Data, &rgeo_proj4_data_type, orig_data);
98
189
  if (!NIL_P(orig_data->original_str)) {
99
- self_data->pj = pj_init_plus(RSTRING_PTR(orig_data->original_str));
190
+ self_data->pj = proj_create(PJ_DEFAULT_CTX, StringValuePtr(orig_data->original_str));
100
191
  }
101
192
  else {
102
- str = pj_get_def(orig_data->pj, 0);
103
- self_data->pj = pj_init_plus(str);
104
- pj_dalloc(str);
193
+ str = proj_as_proj_string(PJ_DEFAULT_CTX, orig_data->pj, PJ_PROJ_4, NULL);
194
+ self_data->pj = proj_create(PJ_DEFAULT_CTX, str);
105
195
  }
106
196
  self_data->original_str = orig_data->original_str;
107
197
  self_data->uses_radians = orig_data->uses_radians;
@@ -112,22 +202,16 @@ static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
112
202
 
113
203
  static VALUE method_proj4_set_value(VALUE self, VALUE str, VALUE uses_radians)
114
204
  {
115
- RGeo_Proj4Data* self_data;
116
- projPJ pj;
205
+ RGeo_Proj4Data *self_data;
117
206
 
118
207
  Check_Type(str, T_STRING);
119
208
 
120
209
  // Clear out any existing value
121
- self_data = RGEO_PROJ4_DATA_PTR(self);
122
- pj = self_data->pj;
123
- if (pj) {
124
- pj_free(pj);
125
- self_data->pj = NULL;
126
- self_data->original_str = Qnil;
127
- }
210
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
211
+ rgeo_proj4_clear_struct(self_data);
128
212
 
129
213
  // Set new data
130
- self_data->pj = pj_init_plus(RSTRING_PTR(str));
214
+ self_data->pj = proj_create(PJ_DEFAULT_CTX, StringValuePtr(str));
131
215
  self_data->original_str = str;
132
216
  self_data->uses_radians = RTEST(uses_radians) ? 1 : 0;
133
217
 
@@ -138,17 +222,18 @@ static VALUE method_proj4_set_value(VALUE self, VALUE str, VALUE uses_radians)
138
222
  static VALUE method_proj4_get_geographic(VALUE self)
139
223
  {
140
224
  VALUE result;
141
- RGeo_Proj4Data* new_data;
142
- RGeo_Proj4Data* self_data;
225
+ RGeo_Proj4Data *new_data;
226
+ RGeo_Proj4Data *self_data;
143
227
 
144
228
  result = Qnil;
145
229
  new_data = ALLOC(RGeo_Proj4Data);
146
230
  if (new_data) {
147
- self_data = RGEO_PROJ4_DATA_PTR(self);
148
- new_data->pj = pj_latlong_from_proj(self_data->pj);
231
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
232
+
233
+ new_data->pj = proj_crs_get_geodetic_crs(PJ_DEFAULT_CTX, self_data->pj);
149
234
  new_data->original_str = Qnil;
150
235
  new_data->uses_radians = self_data->uses_radians;
151
- result = Data_Wrap_Struct(CLASS_OF(self), mark_proj4_func, destroy_proj4_func, new_data);
236
+ result = TypedData_Wrap_Struct(CLASS_OF(self), &rgeo_proj4_data_type, new_data);
152
237
  }
153
238
  return result;
154
239
  }
@@ -156,44 +241,97 @@ static VALUE method_proj4_get_geographic(VALUE self)
156
241
 
157
242
  static VALUE method_proj4_original_str(VALUE self)
158
243
  {
159
- return RGEO_PROJ4_DATA_PTR(self)->original_str;
244
+ RGeo_Proj4Data *data;
245
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
246
+ return data->original_str;
160
247
  }
161
248
 
162
249
 
163
250
  static VALUE method_proj4_uses_radians(VALUE self)
164
251
  {
165
- return RGEO_PROJ4_DATA_PTR(self)->uses_radians ? Qtrue : Qfalse;
252
+ RGeo_Proj4Data *data;
253
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
254
+ return data->uses_radians ? Qtrue : Qfalse;
166
255
  }
167
256
 
168
257
 
169
258
  static VALUE method_proj4_canonical_str(VALUE self)
170
259
  {
171
260
  VALUE result;
172
- projPJ pj;
173
- char* str;
261
+ PJ *pj;
262
+ const char *str;
263
+ RGeo_Proj4Data *data;
174
264
 
175
265
  result = Qnil;
176
- pj = RGEO_PROJ4_DATA_PTR(self)->pj;
266
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
267
+ pj = data->pj;
177
268
  if (pj) {
178
- str = pj_get_def(pj, 0);
269
+ str = proj_as_proj_string(PJ_DEFAULT_CTX, pj, PJ_PROJ_4, NULL);
179
270
  if (str) {
180
271
  result = rb_str_new2(str);
181
- pj_dalloc(str);
182
272
  }
183
273
  }
184
274
  return result;
185
275
  }
186
276
 
277
+ static VALUE method_proj4_wkt_str(VALUE self)
278
+ {
279
+ VALUE result;
280
+ PJ *pj;
281
+ const char *str;
282
+ RGeo_Proj4Data *data;
283
+
284
+ result = Qnil;
285
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
286
+ pj = data->pj;
287
+ if (pj) {
288
+ const char *const options[] = {"MULTILINE=NO", NULL};
289
+ str = proj_as_wkt(PJ_DEFAULT_CTX, pj, WKT_TYPE, options);
290
+ if(str){
291
+ result = rb_str_new2(str);
292
+ }
293
+ }
294
+ return result;
295
+ }
296
+
297
+ static VALUE method_proj4_auth_name_str(VALUE self)
298
+ {
299
+ VALUE result;
300
+ PJ *pj;
301
+ const char *id;
302
+ const char *auth;
303
+ RGeo_Proj4Data *data;
304
+
305
+ result = Qnil;
306
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
307
+ pj = data->pj;
308
+ if (pj) {
309
+ auth = proj_get_id_auth_name(pj, 0);
310
+ id = proj_get_id_code(pj, 0);
311
+ if(id && auth){
312
+ result = rb_sprintf("%s:%s", auth, id);
313
+ }
314
+ }
315
+ return result;
316
+ }
187
317
 
188
318
  static VALUE method_proj4_is_geographic(VALUE self)
189
319
  {
190
320
  VALUE result;
191
- projPJ pj;
321
+ PJ *pj;
322
+ PJ_TYPE proj_type;
323
+ RGeo_Proj4Data *data;
192
324
 
193
325
  result = Qnil;
194
- pj = RGEO_PROJ4_DATA_PTR(self)->pj;
326
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
327
+ pj = data->pj;
195
328
  if (pj) {
196
- result = pj_is_latlong(pj) ? Qtrue : Qfalse;
329
+ proj_type = proj_get_type(pj);
330
+ if(proj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS || proj_type == PJ_TYPE_GEOGRAPHIC_3D_CRS){
331
+ result = Qtrue;
332
+ } else {
333
+ result = Qfalse;
334
+ }
197
335
  }
198
336
  return result;
199
337
  }
@@ -202,12 +340,16 @@ static VALUE method_proj4_is_geographic(VALUE self)
202
340
  static VALUE method_proj4_is_geocentric(VALUE self)
203
341
  {
204
342
  VALUE result;
205
- projPJ pj;
343
+ PJ *pj;
344
+ PJ_TYPE proj_type;
345
+ RGeo_Proj4Data *data;
206
346
 
207
347
  result = Qnil;
208
- pj = RGEO_PROJ4_DATA_PTR(self)->pj;
348
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
349
+ pj = data->pj;
209
350
  if (pj) {
210
- result = pj_is_geocent(pj) ? Qtrue : Qfalse;
351
+ proj_type = proj_get_type(pj);
352
+ result = proj_type == PJ_TYPE_GEOCENTRIC_CRS ? Qtrue : Qfalse;
211
353
  }
212
354
  return result;
213
355
  }
@@ -215,89 +357,130 @@ static VALUE method_proj4_is_geocentric(VALUE self)
215
357
 
216
358
  static VALUE method_proj4_is_valid(VALUE self)
217
359
  {
218
- return RGEO_PROJ4_DATA_PTR(self)->pj ? Qtrue : Qfalse;
360
+ RGeo_Proj4Data *data;
361
+ TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
362
+ return data->pj ? Qtrue : Qfalse;
219
363
  }
220
364
 
221
365
 
222
366
  static VALUE cmethod_proj4_version(VALUE module)
223
367
  {
224
- return INT2NUM(PJ_VERSION);
368
+ return rb_sprintf("%d.%d.%d", PROJ_VERSION_MAJOR, PROJ_VERSION_MINOR, PROJ_VERSION_PATCH);
225
369
  }
226
370
 
227
-
228
- static VALUE cmethod_proj4_transform(VALUE module, VALUE from, VALUE to, VALUE x, VALUE y, VALUE z)
371
+ static VALUE cmethod_proj4_create(VALUE klass, VALUE str, VALUE uses_radians)
229
372
  {
230
373
  VALUE result;
231
- projPJ from_pj;
232
- projPJ to_pj;
233
- double xval, yval, zval;
234
- int err;
374
+ RGeo_Proj4Data* data;
235
375
 
236
376
  result = Qnil;
237
- from_pj = RGEO_PROJ4_DATA_PTR(from)->pj;
238
- to_pj = RGEO_PROJ4_DATA_PTR(to)->pj;
239
- if (from_pj && to_pj) {
240
- xval = rb_num2dbl(x);
241
- yval = rb_num2dbl(y);
242
- zval = 0.0;
243
- if (!NIL_P(z)) {
244
- zval = rb_num2dbl(z);
245
- }
246
- err = pj_transform(from_pj, to_pj, 1, 1, &xval, &yval, NIL_P(z) ? NULL : &zval);
247
- if (!err && xval != HUGE_VAL && yval != HUGE_VAL && (NIL_P(z) || zval != HUGE_VAL)) {
248
- result = rb_ary_new2(NIL_P(z) ? 2 : 3);
249
- rb_ary_push(result, rb_float_new(xval));
250
- rb_ary_push(result, rb_float_new(yval));
251
- if (!NIL_P(z)) {
252
- rb_ary_push(result, rb_float_new(zval));
253
- }
254
- }
377
+ Check_Type(str, T_STRING);
378
+ data = ALLOC(RGeo_Proj4Data);
379
+ if (data) {
380
+ data->pj = proj_create(PJ_DEFAULT_CTX, StringValuePtr(str));
381
+ data->original_str = str;
382
+ data->uses_radians = RTEST(uses_radians) ? 1 : 0;
383
+ result = TypedData_Wrap_Struct(klass, &rgeo_proj4_data_type, data);
384
+ }
385
+ return result;
386
+ }
387
+
388
+ static VALUE cmethod_crs_to_crs_create(VALUE klass, VALUE from, VALUE to)
389
+ {
390
+ VALUE result;
391
+ RGeo_Proj4Data *from_data;
392
+ RGeo_Proj4Data *to_data;
393
+ result = Qnil;
394
+ PJ *from_pj;
395
+ PJ *to_pj;
396
+ PJ *gis_pj;
397
+ PJ *crs_to_crs;
398
+ RGeo_CRSToCRSData* data;
399
+
400
+ TypedData_Get_Struct(from, RGeo_Proj4Data, &rgeo_proj4_data_type, from_data);
401
+ TypedData_Get_Struct(to, RGeo_Proj4Data, &rgeo_proj4_data_type, to_data);
402
+ from_pj = from_data->pj;
403
+ to_pj = to_data->pj;
404
+ crs_to_crs = proj_create_crs_to_crs_from_pj(PJ_DEFAULT_CTX, from_pj, to_pj, 0, NULL);
405
+
406
+ // necessary to use proj_normalize_for_visualization so that we
407
+ // do not have to worry about the order of coordinates in every
408
+ // coord system
409
+ gis_pj = proj_normalize_for_visualization(PJ_DEFAULT_CTX, crs_to_crs);
410
+ if(gis_pj){
411
+ proj_destroy(crs_to_crs);
412
+ crs_to_crs = gis_pj;
413
+ }
414
+ data = ALLOC(RGeo_CRSToCRSData);
415
+ if (data){
416
+ data->crs_to_crs = crs_to_crs;
417
+ result = TypedData_Wrap_Struct(klass, &rgeo_crs_to_crs_data_type, data);
255
418
  }
256
419
  return result;
257
420
  }
258
421
 
259
422
 
260
- static VALUE cmethod_proj4_create(VALUE klass, VALUE str, VALUE uses_radians)
423
+ static VALUE method_crs_to_crs_transform(VALUE self, VALUE x, VALUE y, VALUE z)
261
424
  {
262
425
  VALUE result;
263
- RGeo_Proj4Data* data;
426
+ RGeo_CRSToCRSData *crs_to_crs_data;
427
+ PJ *crs_to_crs_pj;
428
+ double xval, yval, zval;
429
+ PJ_COORD input;
430
+ PJ_COORD output;
264
431
 
265
432
  result = Qnil;
266
- Check_Type(str, T_STRING);
267
- data = ALLOC(RGeo_Proj4Data);
268
- if (data) {
269
- data->pj = pj_init_plus(RSTRING_PTR(str));
270
- data->original_str = str;
271
- data->uses_radians = RTEST(uses_radians) ? 1 : 0;
272
- result = Data_Wrap_Struct(klass, mark_proj4_func, destroy_proj4_func, data);
433
+ TypedData_Get_Struct(self, RGeo_CRSToCRSData, &rgeo_crs_to_crs_data_type, crs_to_crs_data);
434
+ crs_to_crs_pj = crs_to_crs_data->crs_to_crs;
435
+ if(crs_to_crs_pj){
436
+ xval = rb_num2dbl(x);
437
+ yval = rb_num2dbl(y);
438
+ zval = NIL_P(z) ? 0.0 : rb_num2dbl(z);
439
+
440
+ input = proj_coord(xval, yval, zval, HUGE_VAL);
441
+ output = proj_trans(crs_to_crs_pj, PJ_FWD, input);
442
+
443
+ result = rb_ary_new2(NIL_P(z) ? 2 : 3);
444
+ rb_ary_push(result, DBL2NUM(output.xyz.x));
445
+ rb_ary_push(result, DBL2NUM(output.xyz.y));
446
+ if(!NIL_P(z)){
447
+ rb_ary_push(result, DBL2NUM(output.xyz.z));
448
+ }
273
449
  }
274
450
  return result;
275
451
  }
276
452
 
277
-
278
453
  static void rgeo_init_proj4()
279
454
  {
280
455
  VALUE rgeo_module;
281
456
  VALUE coordsys_module;
282
457
  VALUE proj4_class;
458
+ VALUE crs_to_crs_class;
283
459
 
284
460
  rgeo_module = rb_define_module("RGeo");
285
461
  coordsys_module = rb_define_module_under(rgeo_module, "CoordSys");
286
- proj4_class = rb_define_class_under(coordsys_module, "Proj4", rb_cObject);
287
462
 
288
- rb_define_alloc_func(proj4_class, alloc_proj4);
463
+ proj4_class = rb_define_class_under(coordsys_module, "Proj4", rb_cObject);
464
+ rb_define_alloc_func(proj4_class, rgeo_proj4_data_alloc);
289
465
  rb_define_module_function(proj4_class, "_create", cmethod_proj4_create, 2);
290
466
  rb_define_method(proj4_class, "initialize_copy", method_proj4_initialize_copy, 1);
291
467
  rb_define_method(proj4_class, "_set_value", method_proj4_set_value, 2);
292
468
  rb_define_method(proj4_class, "_original_str", method_proj4_original_str, 0);
293
469
  rb_define_method(proj4_class, "_canonical_str", method_proj4_canonical_str, 0);
470
+ rb_define_method(proj4_class, "_as_text", method_proj4_wkt_str, 0);
471
+ rb_define_method(proj4_class, "_auth_name", method_proj4_auth_name_str, 0);
294
472
  rb_define_method(proj4_class, "_valid?", method_proj4_is_valid, 0);
295
473
  rb_define_method(proj4_class, "_geographic?", method_proj4_is_geographic, 0);
296
474
  rb_define_method(proj4_class, "_geocentric?", method_proj4_is_geocentric, 0);
297
475
  rb_define_method(proj4_class, "_radians?", method_proj4_uses_radians, 0);
298
476
  rb_define_method(proj4_class, "_get_geographic", method_proj4_get_geographic, 0);
299
- rb_define_module_function(proj4_class, "_transform_coords", cmethod_proj4_transform, 5);
300
477
  rb_define_module_function(proj4_class, "_proj_version", cmethod_proj4_version, 0);
478
+
479
+
480
+ crs_to_crs_class = rb_define_class_under(coordsys_module, "CRSToCRS", rb_cObject);
481
+ rb_define_alloc_func(crs_to_crs_class, rgeo_crs_to_crs_data_alloc);
482
+ rb_define_module_function(crs_to_crs_class, "_create", cmethod_crs_to_crs_create, 2);
483
+ rb_define_method(crs_to_crs_class, "_transform_coords", method_crs_to_crs_transform, 3);
301
484
  }
302
485
 
303
486
 
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+ module RGeo
5
+ module CoordSys
6
+ # This is a Ruby wrapper around a proj crs_to_crs
7
+ # A crs_to_crs transformation object is a pipeline between two known coordinate reference systems.
8
+ # https://proj.org/development/reference/functions.html#c.proj_create_crs_to_crs
9
+ class CRSToCRS
10
+ attr_writer :from, :to
11
+
12
+ class << self
13
+ def create(from, to)
14
+ crs_to_crs = _create(from, to)
15
+ crs_to_crs.from = from
16
+ crs_to_crs.to = to
17
+ crs_to_crs
18
+ end
19
+ end
20
+ # transform the coordinates from the initial CRS to the destination CRS
21
+ def transform_coords(x, y, z)
22
+ if @from._radians? && @from._geographic?
23
+ x *= ImplHelper::Math::DEGREES_PER_RADIAN
24
+ y *= ImplHelper::Math::DEGREES_PER_RADIAN
25
+ end
26
+ result = _transform_coords(x, y, z)
27
+ if result && @to._radians? && @to._geographic?
28
+ result[0] *= ImplHelper::Math::RADIANS_PER_DEGREE
29
+ result[1] *= ImplHelper::Math::RADIANS_PER_DEGREE
30
+ end
31
+ result
32
+ end
33
+
34
+ def transform(from_geometry, to_factory)
35
+ case from_geometry
36
+ when Feature::Point
37
+ transform_point(from_geometry, to_factory)
38
+ when Feature::Line
39
+ to_factory.line(from_geometry.points.map { |p| transform_point(p, to_factory) })
40
+ when Feature::LinearRing
41
+ transform_linear_ring(from_geometry, to_factory)
42
+ when Feature::LineString
43
+ to_factory.line_string(from_geometry.points.map { |p_| transform_point(p_, to_factory) })
44
+ when Feature::Polygon
45
+ transform_polygon(from_geometry, to_factory)
46
+ when Feature::MultiPoint
47
+ to_factory.multi_point(from_geometry.map { |p| transform_point(p, to_factory) })
48
+ when Feature::MultiLineString
49
+ to_factory.multi_line_string(from_geometry.map { |g| transform(g, to_factory) })
50
+ when Feature::MultiPolygon
51
+ to_factory.multi_polygon(from_geometry.map { |p| transform_polygon(p, to_factory) })
52
+ when Feature::GeometryCollection
53
+ to_factory.collection(from_geometry.map { |g| transform(g, to_factory) })
54
+ end
55
+ end
56
+
57
+ def transform_point(from_point, to_factory)
58
+ from_factory_ = from_point.factory
59
+ from_has_z_ = from_factory_.property(:has_z_coordinate)
60
+ from_has_m_ = from_factory_.property(:has_m_coordinate)
61
+ to_has_z_ = to_factory.property(:has_z_coordinate)
62
+ to_has_m_ = to_factory.property(:has_m_coordinate)
63
+ coords_ = transform_coords(from_point.x, from_point.y, from_has_z_ ? from_point.z : nil)
64
+ return unless coords_
65
+ extras_ = []
66
+ extras_ << coords_[2].to_f if to_has_z_
67
+ if to_has_m_
68
+ extras_ << from_has_m_ ? from_point.m : 0.0
69
+ end
70
+ to_factory.point(coords_[0], coords_[1], *extras_)
71
+ end
72
+
73
+ def transform_linear_ring(from_ring_, to_factory_)
74
+ to_factory_.linear_ring(from_ring_.points[0..-2].map { |p_| transform_point(p_, to_factory_) })
75
+ end
76
+
77
+ def transform_polygon(from_polygon_, to_factory_)
78
+ ext_ = transform_linear_ring(from_polygon_.exterior_ring, to_factory_)
79
+ int_ = from_polygon_.interior_rings.map { |r_| transform_linear_ring(r_, to_factory_) }
80
+ to_factory_.polygon(ext_, int_)
81
+ end
82
+ end
83
+
84
+ # Store of all the created CRSToCRS
85
+ class CRSStore
86
+ include Singleton
87
+ class << self
88
+ def get(from, to)
89
+ instance.get(from, to)
90
+ end
91
+ end
92
+
93
+ Key = Struct.new(:from, :to)
94
+
95
+ def initialize
96
+ @store = Hash.new { |h, k| h[k] = CRSToCRS.create(k.from, k.to) }
97
+ @semaphore = Mutex.new
98
+ end
99
+
100
+ def get(from, to)
101
+ @semaphore.synchronize do
102
+ @store[Key.new(from, to)]
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -41,8 +41,8 @@ module RGeo
41
41
  # there are sometimes multiple ways to express a given coordinate
42
42
  # system.
43
43
 
44
- def eql?(rhs_)
45
- rhs_.class == self.class && rhs_.canonical_hash == canonical_hash && rhs_._radians? == _radians?
44
+ def eql?(other)
45
+ other.class == self.class && other.canonical_hash == canonical_hash && other._radians? == _radians?
46
46
  end
47
47
  alias == eql?
48
48
 
@@ -105,6 +105,21 @@ module RGeo
105
105
  _original_str
106
106
  end
107
107
 
108
+ # Returns the WKT representation of the CRS.
109
+
110
+ def as_text
111
+ _as_text
112
+ end
113
+
114
+ # Returns the string representing the authority and code of the
115
+ # CRS if it exists, nil otherwise.
116
+ #
117
+ # Ex. EPSG:4326
118
+
119
+ def auth_name
120
+ _auth_name
121
+ end
122
+
108
123
  # Returns true if this Proj4 object is a geographic (lat-long)
109
124
  # coordinate system.
110
125
 
@@ -172,7 +187,7 @@ module RGeo
172
187
  if defn_.is_a?(::Hash)
173
188
  defn_ = defn_.map { |k_, v_| v_ ? "+#{k_}=#{v_}" : "+#{k_}" }.join(" ")
174
189
  end
175
- defn_ = defn_.sub(/^(\s*)/, '\1+').gsub(/(\s+)([^+\s])/, '\1+\2') unless defn_ =~ /^\s*\+/
190
+
176
191
  result_ = _create(defn_, opts_[:radians])
177
192
  result_ = nil unless result_._valid?
178
193
  end
@@ -206,18 +221,9 @@ module RGeo
206
221
  # Transforms the given coordinate (x, y, [z]) from one proj4
207
222
  # coordinate system to another. Returns an array with either two
208
223
  # or three elements.
209
-
210
224
  def transform_coords(from_proj_, to_proj_, x_, y_, z_ = nil)
211
- if !from_proj_._radians? && from_proj_._geographic?
212
- x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
213
- y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
214
- end
215
- result_ = _transform_coords(from_proj_, to_proj_, x_, y_, z_)
216
- if result_ && !to_proj_._radians? && to_proj_._geographic?
217
- result_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
218
- result_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
219
- end
220
- result_
225
+ crs_to_crs = CRSStore.get(from_proj_, to_proj_)
226
+ crs_to_crs.transform_coords(x_, y_, z_)
221
227
  end
222
228
 
223
229
  # Low-level geometry transform method.
@@ -225,66 +231,9 @@ module RGeo
225
231
  # The resulting geometry is constructed using the to_factory.
226
232
  # Any projections associated with the factories themselves are
227
233
  # ignored.
228
-
229
234
  def transform(from_proj_, from_geometry_, to_proj_, to_factory_)
230
- case from_geometry_
231
- when Feature::Point
232
- transform_point(from_proj_, from_geometry_, to_proj_, to_factory_)
233
- when Feature::Line
234
- to_factory_.line(from_geometry_.points.map { |p_| transform_point(from_proj_, p_, to_proj_, to_factory_) })
235
- when Feature::LinearRing
236
- transform_linear_ring(from_proj_, from_geometry_, to_proj_, to_factory_)
237
- when Feature::LineString
238
- to_factory_.line_string(from_geometry_.points.map { |p_| transform_point(from_proj_, p_, to_proj_, to_factory_) })
239
- when Feature::Polygon
240
- transform_polygon(from_proj_, from_geometry_, to_proj_, to_factory_)
241
- when Feature::MultiPoint
242
- to_factory_.multi_point(from_geometry_.map { |p_| transform_point(from_proj_, p_, to_proj_, to_factory_) })
243
- when Feature::MultiLineString
244
- to_factory_.multi_line_string(from_geometry_.map { |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
245
- when Feature::MultiPolygon
246
- to_factory_.multi_polygon(from_geometry_.map { |p_| transform_polygon(from_proj_, p_, to_proj_, to_factory_) })
247
- when Feature::GeometryCollection
248
- to_factory_.collection(from_geometry_.map { |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
249
- end
250
- end
251
-
252
- private
253
-
254
- def transform_point(from_proj_, from_point_, to_proj_, to_factory_)
255
- from_factory_ = from_point_.factory
256
- from_has_z_ = from_factory_.property(:has_z_coordinate)
257
- from_has_m_ = from_factory_.property(:has_m_coordinate)
258
- to_has_z_ = to_factory_.property(:has_z_coordinate)
259
- to_has_m_ = to_factory_.property(:has_m_coordinate)
260
- x_ = from_point_.x
261
- y_ = from_point_.y
262
- if !from_proj_._radians? && from_proj_._geographic?
263
- x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
264
- y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
265
- end
266
- coords_ = _transform_coords(from_proj_, to_proj_, x_, y_, from_has_z_ ? from_point_.z : nil)
267
- return unless coords_
268
- if !to_proj_._radians? && to_proj_._geographic?
269
- coords_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
270
- coords_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
271
- end
272
- extras_ = []
273
- extras_ << coords_[2].to_f if to_has_z_
274
- if to_has_m_
275
- extras_ << from_has_m_ ? from_point_.m : 0.0
276
- end
277
- to_factory_.point(coords_[0], coords_[1], *extras_)
278
- end
279
-
280
- def transform_linear_ring(from_proj_, from_ring_, to_proj_, to_factory_)
281
- to_factory_.linear_ring(from_ring_.points[0..-2].map { |p_| transform_point(from_proj_, p_, to_proj_, to_factory_) })
282
- end
283
-
284
- def transform_polygon(from_proj_, from_polygon_, to_proj_, to_factory_)
285
- ext_ = transform_linear_ring(from_proj_, from_polygon_.exterior_ring, to_proj_, to_factory_)
286
- int_ = from_polygon_.interior_rings.map { |r_| transform_linear_ring(from_proj_, r_, to_proj_, to_factory_) }
287
- to_factory_.polygon(ext_, int_)
235
+ crs_to_crs = CRSStore.get(from_proj_, to_proj_)
236
+ crs_to_crs.transform(from_geometry_, to_factory_)
288
237
  end
289
238
  end
290
239
  end
@@ -81,11 +81,12 @@ module RGeo
81
81
  ident_ = ident_.to_s
82
82
  return @cache[ident_] if @cache&.include?(ident_)
83
83
  result_ = nil
84
- if @populate_state == 0
84
+ case @populate_state
85
+ when 0
85
86
  data_ = search_file(ident_)
86
87
  result_ = Entry.new(ident_, authority: @authority, authority_code: @authority ? ident_ : nil, name: data_[1], proj4: data_[2]) if data_
87
88
  @cache[ident_] = result_ if @cache
88
- elsif @populate_state == 1
89
+ when 1
89
90
  search_file(nil)
90
91
  result_ = @cache[ident_]
91
92
  @populate_state = 2
@@ -113,12 +114,10 @@ module RGeo
113
114
  cur_name_ = line_[comment_delim_ + 1..-1].strip
114
115
  line_ = line_[0..comment_delim_ - 1].strip
115
116
  end
116
- unless cur_ident_
117
- if line_ =~ /^<(\w+)>(.*)/
118
- cur_ident_ = Regexp.last_match(1)
119
- cur_text_ = []
120
- line_ = Regexp.last_match(2).strip
121
- end
117
+ if !cur_ident_ && (line_ =~ /^<(\w+)>(.*)/)
118
+ cur_ident_ = Regexp.last_match(1)
119
+ cur_text_ = []
120
+ line_ = Regexp.last_match(2).strip
122
121
  end
123
122
  next unless cur_ident_
124
123
  if line_[-2..-1] == "<>"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RGeo
4
4
  module Proj4
5
- VERSION = "2.0.1"
5
+ VERSION = "3.1.1"
6
6
  end
7
7
  end
data/lib/rgeo/proj4.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "rgeo"
4
4
  require "rgeo/proj4/version"
5
+ require "rgeo/coord_sys/crs_to_crs"
5
6
  require "rgeo/coord_sys/proj4"
6
7
  require "rgeo/coord_sys/srs_database/proj4_data"
7
8
  require "rgeo/coord_sys/proj4_c_impl"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgeo-proj4
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tee Parham, Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-09 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rgeo
@@ -30,28 +30,42 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.11'
33
+ version: '5.14'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.11'
40
+ version: '5.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.9.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.9.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '12.0'
61
+ version: '13.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '12.0'
68
+ version: '13.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake-compiler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.1
69
97
  description: Proj4 extension for rgeo.
70
98
  email:
71
99
  - parhameter@gmail.com, dazuma@gmail.com
@@ -77,6 +105,7 @@ files:
77
105
  - LICENSE.txt
78
106
  - ext/proj4_c_impl/extconf.rb
79
107
  - ext/proj4_c_impl/main.c
108
+ - lib/rgeo/coord_sys/crs_to_crs.rb
80
109
  - lib/rgeo/coord_sys/proj4.rb
81
110
  - lib/rgeo/coord_sys/srs_database/proj4_data.rb
82
111
  - lib/rgeo/proj4.rb
@@ -93,14 +122,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
122
  requirements:
94
123
  - - ">="
95
124
  - !ruby/object:Gem::Version
96
- version: 2.3.0
125
+ version: 2.5.0
97
126
  required_rubygems_version: !ruby/object:Gem::Requirement
98
127
  requirements:
99
128
  - - ">="
100
129
  - !ruby/object:Gem::Version
101
130
  version: '0'
102
131
  requirements: []
103
- rubygems_version: 3.0.3
132
+ rubygems_version: 3.1.4
104
133
  signing_key:
105
134
  specification_version: 4
106
135
  summary: Proj4 extension for rgeo.