rgeo 0.2.3 → 0.2.4

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,10 @@
1
+ === 0.2.4 / 2010-12-31
2
+
3
+ * Several bugs were preventing the low-level Proj4 transform functions from working at all. Fixed. (Reported by mRg.)
4
+ * The GEOS factories over-optimized projection casts, sometimes resulting in proj4 transformations not getting applied. Fixed. (Reported by mRg.)
5
+ * Proj4 objects now have a flag to indicate whether geographic coordinate systems should be in radians. The (undocumented) radians option is no longer supported in transform_coords.
6
+ * Disabled the spatialreference.org tests for the time being because the site seems to be offline.
7
+
1
8
  === 0.2.3 / 2010-12-19
2
9
 
3
10
  * The "simpler mercator" geographic type incorrectly reported EPSG 3857 instead of EPSG 3785 for the projection. Dyslexia fixed.
data/Version CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.2.4
@@ -67,6 +67,7 @@ RGEO_BEGIN_C
67
67
  typedef struct {
68
68
  projPJ pj;
69
69
  VALUE original_str;
70
+ char uses_radians;
70
71
  } RGeo_Proj4Data;
71
72
 
72
73
 
@@ -99,6 +100,7 @@ static VALUE alloc_proj4(VALUE klass)
99
100
  if (data) {
100
101
  data->pj = NULL;
101
102
  data->original_str = Qnil;
103
+ data->uses_radians = 0;
102
104
  result = Data_Wrap_Struct(klass, mark_proj4_func, destroy_proj4_func, data);
103
105
  }
104
106
  return result;
@@ -108,16 +110,19 @@ static VALUE alloc_proj4(VALUE klass)
108
110
  static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
109
111
  {
110
112
  // Clear out any existing value
111
- projPJ pj = RGEO_PROJ4_DATA_PTR(self)->pj;
113
+ RGeo_Proj4Data* self_data = RGEO_PROJ4_DATA_PTR(self);
114
+ projPJ pj = self_data->pj;
112
115
  if (pj) {
113
116
  pj_free(pj);
114
- RGEO_PROJ4_DATA_PTR(self)->pj = NULL;
115
- RGEO_PROJ4_DATA_PTR(self)->original_str = Qnil;
117
+ self_data->pj = NULL;
118
+ self_data->original_str = Qnil;
116
119
  }
117
120
 
118
121
  // Copy value from orig
119
- RGEO_PROJ4_DATA_PTR(self)->pj = RGEO_PROJ4_DATA_PTR(orig)->pj;
120
- RGEO_PROJ4_DATA_PTR(self)->original_str = RGEO_PROJ4_DATA_PTR(orig)->original_str;
122
+ RGeo_Proj4Data* orig_data = RGEO_PROJ4_DATA_PTR(orig);
123
+ self_data->pj = orig_data->pj;
124
+ self_data->original_str = orig_data->original_str;
125
+ self_data->uses_radians = orig_data->uses_radians;
121
126
 
122
127
  return self;
123
128
  }
@@ -126,11 +131,13 @@ static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig)
126
131
  static VALUE method_proj4_get_geographic(VALUE self)
127
132
  {
128
133
  VALUE result = Qnil;
129
- RGeo_Proj4Data* data = ALLOC(RGeo_Proj4Data);
130
- if (data) {
131
- data->pj = pj_latlong_from_proj(RGEO_PROJ4_DATA_PTR(self)->pj);
132
- data->original_str = Qnil;
133
- result = Data_Wrap_Struct(CLASS_OF(self), mark_proj4_func, destroy_proj4_func, data);
134
+ RGeo_Proj4Data* new_data = ALLOC(RGeo_Proj4Data);
135
+ if (new_data) {
136
+ RGeo_Proj4Data* self_data = RGEO_PROJ4_DATA_PTR(self);
137
+ new_data->pj = pj_latlong_from_proj(self_data->pj);
138
+ new_data->original_str = Qnil;
139
+ new_data->uses_radians = self_data->uses_radians;
140
+ result = Data_Wrap_Struct(CLASS_OF(self), mark_proj4_func, destroy_proj4_func, new_data);
134
141
  }
135
142
  return result;
136
143
  }
@@ -142,6 +149,12 @@ static VALUE method_proj4_original_str(VALUE self)
142
149
  }
143
150
 
144
151
 
152
+ static VALUE method_proj4_uses_radians(VALUE self)
153
+ {
154
+ return RGEO_PROJ4_DATA_PTR(self)->uses_radians ? Qtrue : Qfalse;
155
+ }
156
+
157
+
145
158
  static VALUE method_proj4_canonical_str(VALUE self)
146
159
  {
147
160
  VALUE result = Qnil;
@@ -211,7 +224,7 @@ static VALUE cmethod_proj4_transform(VALUE method, VALUE from, VALUE to, VALUE x
211
224
  }
212
225
 
213
226
 
214
- static VALUE cmethod_proj4_create(VALUE klass, VALUE str)
227
+ static VALUE cmethod_proj4_create(VALUE klass, VALUE str, VALUE uses_radians)
215
228
  {
216
229
  VALUE result = Qnil;
217
230
  Check_Type(str, T_STRING);
@@ -219,6 +232,7 @@ static VALUE cmethod_proj4_create(VALUE klass, VALUE str)
219
232
  if (data) {
220
233
  data->pj = pj_init_plus(RSTRING_PTR(str));
221
234
  data->original_str = str;
235
+ data->uses_radians = RTEST(uses_radians) ? 1 : 0;
222
236
  result = Data_Wrap_Struct(klass, mark_proj4_func, destroy_proj4_func, data);
223
237
  }
224
238
  return result;
@@ -230,13 +244,14 @@ static void rgeo_init_proj4()
230
244
  VALUE rgeo_module = rb_define_module("RGeo");
231
245
  VALUE coordsys_module = rb_define_module_under(rgeo_module, "CoordSys");
232
246
  VALUE proj4_class = rb_define_class_under(coordsys_module, "Proj4", rb_cObject);
233
- rb_define_module_function(proj4_class, "_create", cmethod_proj4_create, 1);
247
+ rb_define_module_function(proj4_class, "_create", cmethod_proj4_create, 2);
234
248
  rb_define_method(proj4_class, "initialize_copy", method_proj4_initialize_copy, 1);
235
249
  rb_define_method(proj4_class, "_original_str", method_proj4_original_str, 0);
236
250
  rb_define_method(proj4_class, "_canonical_str", method_proj4_canonical_str, 0);
237
251
  rb_define_method(proj4_class, "_valid?", method_proj4_is_valid, 0);
238
252
  rb_define_method(proj4_class, "_geographic?", method_proj4_is_geographic, 0);
239
253
  rb_define_method(proj4_class, "_geocentric?", method_proj4_is_geocentric, 0);
254
+ rb_define_method(proj4_class, "_radians?", method_proj4_uses_radians, 0);
240
255
  rb_define_method(proj4_class, "_get_geographic", method_proj4_get_geographic, 0);
241
256
  rb_define_module_function(proj4_class, "_transform_coords", cmethod_proj4_transform, 5);
242
257
  }
@@ -78,7 +78,7 @@ module RGeo
78
78
  # system.
79
79
 
80
80
  def eql?(rhs_)
81
- rhs_.class == self.class && rhs_.canonical_hash == canonical_hash
81
+ rhs_.class == self.class && rhs_.canonical_hash == canonical_hash && rhs_._radians? == _radians?
82
82
  end
83
83
  alias_method :==, :eql?
84
84
 
@@ -137,6 +137,14 @@ module RGeo
137
137
  end
138
138
 
139
139
 
140
+ # Returns true if this Proj4 object uses radians rather than degrees
141
+ # if it is a geographic coordinate system.
142
+
143
+ def radians?
144
+ _radians?
145
+ end
146
+
147
+
140
148
  # Get the geographic (unprojected lat-long) coordinate system
141
149
  # corresponding to this coordinate system; i.e. the one that uses
142
150
  # the same ellipsoid and datum.
@@ -161,8 +169,21 @@ module RGeo
161
169
  # Create a new Proj4 object, given a definition, which may be
162
170
  # either a string or a hash. Returns nil if the given definition
163
171
  # is invalid or Proj4 is not supported.
172
+ #
173
+ # Recognized options include:
174
+ #
175
+ # <tt>:radians</tt>::
176
+ # If set to true, then this proj4 will represent geographic
177
+ # (latitude/longitude) coordinates in radians rather than
178
+ # degrees. If this is a geographic coordinate system, then its
179
+ # units will be in radians. If this is a projected coordinate
180
+ # system, then its units will be unchanged, but any geographic
181
+ # coordinate system obtained using get_geographic will use
182
+ # radians as its units. If this is a geocentric or other type of
183
+ # coordinate system, this has no effect. Default is false.
184
+ # (That is all coordinates are in degrees by default.)
164
185
 
165
- def create(defn_)
186
+ def create(defn_, opts_={})
166
187
  result_ = nil
167
188
  if supported?
168
189
  if defn_.kind_of?(::Hash)
@@ -171,7 +192,7 @@ module RGeo
171
192
  unless defn_ =~ /^\s*\+/
172
193
  defn_ = defn_.sub(/^(\s*)/, '\1+').gsub(/(\s+)([^+\s])/, '\1+\2')
173
194
  end
174
- result_ = _create(defn_)
195
+ result_ = _create(defn_, opts_[:radians])
175
196
  result_ = nil unless result_._valid?
176
197
  end
177
198
  result_
@@ -182,8 +203,8 @@ module RGeo
182
203
  # either a string or a hash. Raises Error::UnsupportedOperation
183
204
  # if the given definition is invalid or Proj4 is not supported.
184
205
 
185
- def new(defn_)
186
- result_ = create(defn_)
206
+ def new(defn_, opts_={})
207
+ result_ = create(defn_, opts_)
187
208
  unless result_
188
209
  raise Error::UnsupportedOperation, "Proj4 not supported in this installation"
189
210
  end
@@ -196,14 +217,13 @@ module RGeo
196
217
  # coordinate system to another. Returns an array with either two
197
218
  # or three elements.
198
219
 
199
- def transform_coords(from_proj_, to_proj_, x_, y_, z_=nil, opts_={})
200
- degrees_ = !opts_[:radians]
201
- if degrees_ && from_proj_._geographic?
220
+ def transform_coords(from_proj_, to_proj_, x_, y_, z_=nil)
221
+ if !from_proj_._radians? && from_proj_._geographic?
202
222
  x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
203
223
  y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
204
224
  end
205
225
  result_ = _transform_coords(from_proj_, to_proj_, x_, y_, z_)
206
- if result_ && degrees_ && to_proj_._geographic?
226
+ if result_ && !to_proj_._radians? && to_proj_._geographic?
207
227
  result_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
208
228
  result_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
209
229
  end
@@ -222,11 +242,11 @@ module RGeo
222
242
  when Feature::Point
223
243
  _transform_point(from_proj_, from_geometry_, to_proj_, to_factory_)
224
244
  when Feature::Line
225
- to_factory_.line(from_geometry_.points.map{ |p_| transform(from_proj_, p_, to_proj_, to_factory_) })
245
+ to_factory_.line(from_geometry_.points.map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
226
246
  when Feature::LinearRing
227
247
  _transform_linear_ring(from_proj_, from_geometry_, to_proj_, to_factory_)
228
248
  when Feature::LineString
229
- to_factory_.line_string(from_geometry_.points.map{ |p_| transform(from_proj_, p_, to_proj_, to_factory_) })
249
+ to_factory_.line_string(from_geometry_.points.map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
230
250
  when Feature::Polygon
231
251
  _transform_polygon(from_proj_, from_geometry_, to_proj_, to_factory_)
232
252
  when Feature::MultiPoint
@@ -247,17 +267,30 @@ module RGeo
247
267
  from_has_m_ = from_factory_.property(:has_m_coordinate)
248
268
  to_has_z_ = to_factory_.property(:has_z_coordinate)
249
269
  to_has_m_ = to_factory_.property(:has_m_coordinate)
250
- coords_ = _transform_coords(from_proj_, to_proj_, from_point_.x, from_point_.y,
251
- from_has_z_ ? from_point_.z : nil)
252
- extras_ = []
253
- extras_ << coords_[2].to_f if to_has_z_
254
- extras_ << from_has_m_ ? from_point_.m : 0.0 if to_has_m_?
255
- to_factory_.point(coords_[0], coords_[1], extras_)
270
+ x_ = from_point_.x
271
+ y_ = from_point_.y
272
+ if !from_proj_._radians? && from_proj_._geographic?
273
+ x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
274
+ y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
275
+ end
276
+ coords_ = _transform_coords(from_proj_, to_proj_, x_, y_, from_has_z_ ? from_point_.z : nil)
277
+ if coords_
278
+ if !to_proj_._radians? && to_proj_._geographic?
279
+ coords_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
280
+ coords_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
281
+ end
282
+ extras_ = []
283
+ extras_ << coords_[2].to_f if to_has_z_
284
+ extras_ << from_has_m_ ? from_point_.m : 0.0 if to_has_m_
285
+ to_factory_.point(coords_[0], coords_[1], *extras_)
286
+ else
287
+ nil
288
+ end
256
289
  end
257
290
 
258
291
 
259
292
  def _transform_linear_ring(from_proj_, from_ring_, to_proj_, to_factory_) # :nodoc:
260
- to_factory_.linear_ring(from_ring_.points[0..-2].map{ |p_| transform(from_proj_, p_, to_proj_, to_factory_) })
293
+ to_factory_.linear_ring(from_ring_.points[0..-2].map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
261
294
  end
262
295
 
263
296
 
@@ -106,7 +106,7 @@ module RGeo
106
106
  # Factory equivalence test.
107
107
 
108
108
  def eql?(rhs_)
109
- rhs_.is_a?(Factory) && rhs_.srid == _srid && rhs_._buffer_resolution == _buffer_resolution && rhs_._flags == _flags
109
+ rhs_.is_a?(Factory) && rhs_.srid == _srid && rhs_._buffer_resolution == _buffer_resolution && rhs_._flags == _flags && rhs_.proj4 == @proj4
110
110
  end
111
111
  alias_method :==, :eql?
112
112
 
@@ -257,14 +257,16 @@ module RGeo
257
257
  return nil unless Geos.supported?
258
258
  keep_subtype_ = flags_[:keep_subtype]
259
259
  force_new_ = flags_[:force_new]
260
+ project_ = flags_[:project]
260
261
  type_ = original_.geometry_type
261
262
  ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
262
263
  case original_
263
264
  when GeometryImpl
264
265
  # Optimization if we're just changing factories, but the
265
- # factories are zm-compatible.
266
+ # factories are zm-compatible and proj4-compatible.
266
267
  if original_.factory != self && ntype_ == type_ &&
267
- original_.factory._flags & 0x6 == _flags & 0x6
268
+ original_.factory._flags & 0x6 == _flags & 0x6 &&
269
+ (!project_ || original_.factory.proj4 == @proj4)
268
270
  then
269
271
  result_ = original_.dup
270
272
  result_._set_factory(self)
@@ -273,6 +275,7 @@ module RGeo
273
275
  # LineString conversion optimization.
274
276
  if (original_.factory != self || ntype_ != type_) &&
275
277
  original_.factory._flags & 0x6 == _flags & 0x6 &&
278
+ (!project_ || original_.factory.proj4 == @proj4) &&
276
279
  type_.subtype_of?(Feature::LineString) && ntype_.subtype_of?(Feature::LineString)
277
280
  then
278
281
  return IMPL_CLASSES[ntype_]._copy_from(self, original_)
@@ -236,13 +236,16 @@ module RGeo
236
236
  return nil unless Geos.supported?
237
237
  keep_subtype_ = flags_[:keep_subtype]
238
238
  force_new_ = flags_[:force_new]
239
+ project_ = flags_[:project]
239
240
  type_ = original_.geometry_type
240
241
  ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
241
242
  case original_
242
243
  when ZMGeometryImpl
243
244
  # Optimization if we're just changing factories, but to
244
245
  # another ZM factory.
245
- if original_.factory != self && ntype_ == type_
246
+ if original_.factory != self && ntype_ == type_ &&
247
+ (!project_ || original_.factory.proj4 == @proj4)
248
+ then
246
249
  zresult_ = original_.z_geometry.dup
247
250
  zresult_._set_factory(@zfactory)
248
251
  mresult_ = original_.m_geometry.dup
@@ -251,6 +254,7 @@ module RGeo
251
254
  end
252
255
  # LineString conversion optimization.
253
256
  if (original_.factory != self || ntype_ != type_) &&
257
+ (!project_ || original_.factory.proj4 == @proj4) &&
254
258
  type_.subtype_of?(Feature::LineString) && ntype_.subtype_of?(Feature::LineString)
255
259
  then
256
260
  klass_ = Factory::IMPL_CLASSES[ntype_]
@@ -92,15 +92,15 @@ 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')
95
+ geography_ = RGeo::CoordSys::Proj4.create('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', :radians => true)
96
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, :radians => true))
98
- _assert_xy_close(_project_merc(0.01, 0.01), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 0.01, 0.01, nil, :radians => true))
99
- _assert_xy_close(_project_merc(1, 1), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, 1, 1, nil, :radians => true))
100
- _assert_xy_close(_project_merc(-1, -1), RGeo::CoordSys::Proj4.transform_coords(geography_, projection_, -1, -1, nil, :radians => true))
101
- _assert_xy_close(_unproject_merc(0, 0), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 0, 0, nil, :radians => true))
102
- _assert_xy_close(_unproject_merc(10000, 10000), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, 10000, 10000, nil, :radians => true))
103
- _assert_xy_close(_unproject_merc(-20000000, -20000000), RGeo::CoordSys::Proj4.transform_coords(projection_, geography_, -20000000, -20000000, nil, :radians => true))
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
 
@@ -111,6 +111,26 @@ module RGeo
111
111
  end
112
112
 
113
113
 
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)
117
+ proj_point_ = projection_.parse_wkt('POINT(473600.5000000000000000 186659.7999999999883585)')
118
+ geo_point_ = RGeo::Feature.cast(proj_point_, :project => true, :factory => geography_)
119
+ _assert_close_enough(-0.9393598527244420, geo_point_.x)
120
+ _assert_close_enough(51.5740106527552697, geo_point_.y)
121
+ end
122
+
123
+
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)
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_)
129
+ _assert_close_enough(-0.9393598527244420, geo_point_.x)
130
+ _assert_close_enough(51.5740106527552697, geo_point_.y)
131
+ end
132
+
133
+
114
134
  end
115
135
 
116
136
  end
@@ -63,7 +63,7 @@ module RGeo
63
63
  end
64
64
 
65
65
 
66
- end
66
+ end if false
67
67
 
68
68
  end
69
69
  end
@@ -75,7 +75,7 @@ module RGeo
75
75
  end
76
76
 
77
77
 
78
- end
78
+ end if false
79
79
 
80
80
  end
81
81
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 3
9
- version: 0.2.3
8
+ - 4
9
+ version: 0.2.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Daniel Azuma
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-19 00:00:00 -08:00
17
+ date: 2010-12-31 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies: []
20
20