rgeo 0.2.3 → 0.2.4

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