rgeo 3.0.0.pre.rc.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -1
  3. data/ext/geos_c_impl/analysis.c +26 -23
  4. data/ext/geos_c_impl/analysis.h +8 -5
  5. data/ext/geos_c_impl/coordinates.c +27 -21
  6. data/ext/geos_c_impl/coordinates.h +5 -2
  7. data/ext/geos_c_impl/errors.c +15 -8
  8. data/ext/geos_c_impl/errors.h +4 -1
  9. data/ext/geos_c_impl/extconf.rb +40 -30
  10. data/ext/geos_c_impl/factory.c +405 -389
  11. data/ext/geos_c_impl/factory.h +71 -49
  12. data/ext/geos_c_impl/geometry.c +485 -408
  13. data/ext/geos_c_impl/geometry.h +5 -5
  14. data/ext/geos_c_impl/geometry_collection.c +269 -198
  15. data/ext/geos_c_impl/geometry_collection.h +6 -7
  16. data/ext/geos_c_impl/globals.c +99 -21
  17. data/ext/geos_c_impl/globals.h +3 -2
  18. data/ext/geos_c_impl/line_string.c +261 -220
  19. data/ext/geos_c_impl/line_string.h +5 -6
  20. data/ext/geos_c_impl/main.c +8 -9
  21. data/ext/geos_c_impl/point.c +62 -65
  22. data/ext/geos_c_impl/point.h +4 -5
  23. data/ext/geos_c_impl/polygon.c +121 -90
  24. data/ext/geos_c_impl/polygon.h +11 -9
  25. data/ext/geos_c_impl/preface.h +4 -13
  26. data/ext/geos_c_impl/ruby_more.c +39 -37
  27. data/ext/geos_c_impl/ruby_more.h +11 -2
  28. data/lib/rgeo/cartesian/analysis.rb +5 -3
  29. data/lib/rgeo/cartesian/bounding_box.rb +74 -79
  30. data/lib/rgeo/cartesian/calculations.rb +20 -26
  31. data/lib/rgeo/cartesian/factory.rb +52 -89
  32. data/lib/rgeo/cartesian/feature_methods.rb +0 -5
  33. data/lib/rgeo/cartesian/interface.rb +6 -5
  34. data/lib/rgeo/cartesian/planar_graph.rb +10 -16
  35. data/lib/rgeo/cartesian/sweepline_intersector.rb +1 -3
  36. data/lib/rgeo/cartesian/valid_op.rb +1 -3
  37. data/lib/rgeo/coord_sys/cs/entities.rb +299 -99
  38. data/lib/rgeo/coord_sys/cs/factories.rb +0 -2
  39. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +85 -37
  40. data/lib/rgeo/coord_sys.rb +1 -9
  41. data/lib/rgeo/feature/curve.rb +0 -11
  42. data/lib/rgeo/feature/factory.rb +26 -36
  43. data/lib/rgeo/feature/factory_generator.rb +6 -11
  44. data/lib/rgeo/feature/geometry.rb +41 -40
  45. data/lib/rgeo/feature/geometry_collection.rb +3 -4
  46. data/lib/rgeo/feature/line_string.rb +1 -2
  47. data/lib/rgeo/feature/linear_ring.rb +0 -1
  48. data/lib/rgeo/feature/multi_curve.rb +0 -6
  49. data/lib/rgeo/feature/multi_surface.rb +0 -1
  50. data/lib/rgeo/feature/point.rb +0 -1
  51. data/lib/rgeo/feature/polygon.rb +1 -2
  52. data/lib/rgeo/feature/surface.rb +0 -1
  53. data/lib/rgeo/feature/types.rb +73 -83
  54. data/lib/rgeo/geographic/factory.rb +93 -119
  55. data/lib/rgeo/geographic/interface.rb +62 -116
  56. data/lib/rgeo/geographic/projected_feature_methods.rb +2 -16
  57. data/lib/rgeo/geographic/projected_window.rb +36 -22
  58. data/lib/rgeo/geographic/{proj4_projector.rb → projector.rb} +3 -3
  59. data/lib/rgeo/geographic/simple_mercator_projector.rb +24 -21
  60. data/lib/rgeo/geographic/spherical_feature_methods.rb +8 -8
  61. data/lib/rgeo/geographic/spherical_math.rb +17 -20
  62. data/lib/rgeo/geographic.rb +1 -1
  63. data/lib/rgeo/geos/capi_factory.rb +70 -124
  64. data/lib/rgeo/geos/capi_feature_classes.rb +0 -29
  65. data/lib/rgeo/geos/ffi_factory.rb +90 -131
  66. data/lib/rgeo/geos/ffi_feature_methods.rb +73 -128
  67. data/lib/rgeo/geos/interface.rb +21 -36
  68. data/lib/rgeo/geos/utils.rb +3 -3
  69. data/lib/rgeo/geos/zm_factory.rb +53 -76
  70. data/lib/rgeo/geos/zm_feature_methods.rb +16 -34
  71. data/lib/rgeo/geos.rb +2 -5
  72. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +5 -18
  73. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -2
  74. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +18 -42
  75. data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -13
  76. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +16 -25
  77. data/lib/rgeo/impl_helper/utils.rb +21 -0
  78. data/lib/rgeo/impl_helper/valid_op.rb +12 -16
  79. data/lib/rgeo/impl_helper/validity_check.rb +3 -3
  80. data/lib/rgeo/version.rb +1 -1
  81. data/lib/rgeo/wkrep/wkb_generator.rb +73 -63
  82. data/lib/rgeo/wkrep/wkb_parser.rb +33 -31
  83. data/lib/rgeo/wkrep/wkt_generator.rb +52 -45
  84. data/lib/rgeo/wkrep/wkt_parser.rb +48 -35
  85. data/lib/rgeo.rb +1 -3
  86. metadata +10 -9
@@ -134,12 +134,19 @@ module RGeo
134
134
  # Highest possible value for local datum types.
135
135
  LD_MAX = 32_767
136
136
 
137
+ # Flags indicating parts of domain covered by a convex hull. These flags can be combined. For
138
+ # example, the value 3 corresponds to a combination of CT_DF_Inside and MF_DF_Outside, which
139
+ # means that some parts of the convex hull are inside the domain, and some parts of the convex
140
+ # hull are outside the domain
141
+ CT_DF_INSIDE = 1
142
+ CT_DF_OUTSIDE = 2
143
+ CT_DF_DISCONTINUOUS = 4
144
+
137
145
  # This is a base class for all OGC coordinate system objects.
138
146
  # This includes both interfaces and data types from the OGC
139
147
  # Coordinate Transformation spec.
140
148
  #
141
149
  # This is a non-instantiable abstract class.
142
-
143
150
  class Base
144
151
  # Standard object inspection output
145
152
 
@@ -150,8 +157,8 @@ module RGeo
150
157
  # Tests for equality. Two objects are defined as equal if they
151
158
  # have the same type (class) and the same WKT representation.
152
159
 
153
- def eql?(rhs)
154
- rhs.class == self.class && rhs.to_wkt == to_wkt
160
+ def eql?(other)
161
+ other.class == self.class && other.to_wkt == to_wkt
155
162
  end
156
163
  alias == eql?
157
164
 
@@ -172,19 +179,21 @@ module RGeo
172
179
  # <tt>:standard_brackets</tt>
173
180
  # If true, outputs parentheses rather than square
174
181
  # brackets. Default is false.
175
- def to_wkt(standard_brackets = false)
182
+ def to_wkt(standard_brackets: false)
176
183
  open, close = brackets(standard_brackets)
177
184
  content = wkt_content(standard_brackets).map { |obj| ",#{obj}" }.join
178
- if defined?(@authority) && @authority
179
- authority = ",AUTHORITY#{open}#{@authority.inspect},#{@authority_code.inspect}#{close}"
180
- else
181
- authority = ""
182
- end
183
- if defined?(@extensions) && @extensions
184
- extensions = @extensions.map { |k, v| ",EXTENSION#{open}#{k.inspect},#{v.inspect}#{close}" }.join
185
- else
186
- extensions = ""
187
- end
185
+ authority =
186
+ if defined?(@authority) && @authority
187
+ ",AUTHORITY#{open}#{@authority.inspect},#{@authority_code.inspect}#{close}"
188
+ else
189
+ ""
190
+ end
191
+ extensions =
192
+ if defined?(@extensions) && @extensions
193
+ @extensions.map { |k, v| ",EXTENSION#{open}#{k.inspect},#{v.inspect}#{close}" }.join
194
+ else
195
+ ""
196
+ end
188
197
  "#{wkt_typename}#{open}#{@name.inspect}#{content}#{extensions}#{authority}#{close}"
189
198
  end
190
199
 
@@ -197,12 +206,11 @@ module RGeo
197
206
  def marshal_load(data) # :nodoc:
198
207
  data = data["wkt"] if data.is_a?(Hash)
199
208
  temp = CS.create_from_wkt(data)
200
- if temp.class == self.class
201
- temp.instance_variables.each do |iv|
202
- instance_variable_set(iv, temp.instance_variable_get(iv))
203
- end
204
- else
205
- raise TypeError, "Bad Marshal data"
209
+
210
+ raise TypeError, "Bad Marshal data" unless temp.instance_of?(self.class)
211
+
212
+ temp.instance_variables.each do |iv|
213
+ instance_variable_set(iv, temp.instance_variable_get(iv))
206
214
  end
207
215
  end
208
216
 
@@ -214,12 +222,11 @@ module RGeo
214
222
 
215
223
  def init_with(coder) # :nodoc:
216
224
  temp = CS.create_from_wkt(coder.type == :scalar ? coder.scalar : coder["wkt"])
217
- if temp.class == self.class
218
- temp.instance_variables.each do |iv|
219
- instance_variable_set(iv, temp.instance_variable_get(iv))
220
- end
221
- else
222
- raise TypeError, "Bad YAML data"
225
+
226
+ raise TypeError, "Bad YAML data" unless temp.instance_of?(self.class)
227
+
228
+ temp.instance_variables.each do |iv|
229
+ instance_variable_set(iv, temp.instance_variable_get(iv))
223
230
  end
224
231
  end
225
232
 
@@ -238,7 +245,6 @@ module RGeo
238
245
  #
239
246
  # Details of axis. This is used to label axes, and indicate the
240
247
  # orientation.
241
-
242
248
  class AxisInfo < Base
243
249
  # :stopdoc:
244
250
  NAMES_BY_VALUE = %w[OTHER NORTH SOUTH EAST WEST UP DOWN].freeze
@@ -246,12 +252,13 @@ module RGeo
246
252
 
247
253
  def initialize(name, orientation) # :nodoc:
248
254
  @name = name
249
- case orientation
250
- when String, Symbol
251
- @orientation = NAMES_BY_VALUE.index(orientation.to_s.upcase).to_i
252
- else
253
- @orientation = orientation.to_i
254
- end
255
+ @orientation =
256
+ case orientation
257
+ when String, Symbol
258
+ NAMES_BY_VALUE.index(orientation.to_s.upcase).to_i
259
+ else
260
+ orientation.to_i
261
+ end
255
262
  end
256
263
 
257
264
  # Human readable name for axis. Possible values are "X", "Y",
@@ -293,7 +300,6 @@ module RGeo
293
300
  # projected coordinate system. The angular units of parameter
294
301
  # values match the angular units of the geographic coordinate
295
302
  # system that the projected coordinate system is based on.
296
-
297
303
  class ProjectionParameter < Base
298
304
  def initialize(name, value) # :nodoc:
299
305
  @name = name
@@ -331,15 +337,14 @@ module RGeo
331
337
  # Wolf parameters should be applied to geocentric coordinates, where
332
338
  # the X axis points towards the Greenwich Prime Meridian, the Y axis
333
339
  # points East, and the Z axis points North.
334
-
335
340
  class WGS84ConversionInfo < Base
336
- def initialize(dx, dy, dz, ex, ey, ez, ppm) # :nodoc:
337
- @dx = dx.to_f
338
- @dy = dy.to_f
339
- @dz = dz.to_f
340
- @ex = ex.to_f
341
- @ey = ey.to_f
342
- @ez = ez.to_f
341
+ def initialize(dx_meters, dy_meters, dz_meters, ex_arc_seconds, ey_arc_seconds, ez_arc_seconds, ppm) # :nodoc:
342
+ @dx = dx_meters.to_f
343
+ @dy = dy_meters.to_f
344
+ @dz = dz_meters.to_f
345
+ @ex = ex_arc_seconds.to_f
346
+ @ey = ey_arc_seconds.to_f
347
+ @ez = ez_arc_seconds.to_f
343
348
  @ppm = ppm.to_f
344
349
  end
345
350
 
@@ -364,7 +369,7 @@ module RGeo
364
369
  # Bursa Wolf scaling in in parts per million.
365
370
  attr_reader :ppm
366
371
 
367
- def to_wkt(standard_brackets = false)
372
+ def to_wkt(standard_brackets: false)
368
373
  open, close = brackets(standard_brackets)
369
374
  "TOWGS84#{open}#{@dx},#{@dy},#{@dz},#{@ex},#{@ey},#{@ez},#{@ppm}#{close}"
370
375
  end
@@ -375,8 +380,8 @@ module RGeo
375
380
  # The Bursa Wolf shift should be in meters, the rotation in arc
376
381
  # seconds, and the scaling in parts per million.
377
382
 
378
- def create(dx, dy, dz, ex, ey, ez, ppm)
379
- new(dx, dy, dz, ex, ey, ez, ppm)
383
+ def create(dx_meters, dy_meters, dz_meters, ex_arc_seconds, ey_arc_seconds, ez_arc_seconds, ppm)
384
+ new(dx_meters, dy_meters, dz_meters, ex_arc_seconds, ey_arc_seconds, ez_arc_seconds, ppm)
380
385
  end
381
386
  end
382
387
  end
@@ -419,9 +424,9 @@ module RGeo
419
424
  # * <b>alias</b>: an alias
420
425
  # * <b>remarks</b>: provider-supplied remarks.
421
426
  # * <b>extensions</b>: a hash of extension keys and values
422
-
423
427
  class Info < Base
424
- def initialize(name, authority = nil, authority_code = nil, abbreviation = nil, init_alias = nil, remarks = nil, extensions = nil) # :nodoc:
428
+ def initialize(name, authority = nil, authority_code = nil, abbreviation = nil, init_alias = nil,
429
+ remarks = nil, extensions = nil) # :nodoc:
425
430
  @name = name
426
431
  @authority = authority ? authority.to_s : nil
427
432
  @authority_code = authority_code ? authority_code.to_s : nil
@@ -480,7 +485,6 @@ module RGeo
480
485
  # Normally, you will instantiate one of the subclasses LinearUnit or
481
486
  # AngularUnit. However, it is possible to instantiate Unit if it is
482
487
  # not clear whether the data refers to a LinearUnit or AngularUnit.
483
-
484
488
  class Unit < Info
485
489
  def initialize(name, conversion_factor, *optional) # :nodoc:
486
490
  super(name, *optional)
@@ -517,7 +521,6 @@ module RGeo
517
521
  # == OGC spec description
518
522
  #
519
523
  # Definition of linear units.
520
-
521
524
  class LinearUnit < Unit
522
525
  # Returns the number of meters per LinearUnit.
523
526
  # Also available as Unit#conversion_factor.
@@ -540,7 +543,6 @@ module RGeo
540
543
  # == OGC spec description
541
544
  #
542
545
  # Definition of angular units.
543
-
544
546
  class AngularUnit < Unit
545
547
  # Returns the number of radians per AngularUnit.
546
548
  # Also available as Unit#conversion_factor.
@@ -563,7 +565,6 @@ module RGeo
563
565
  # == OGC spec description
564
566
  #
565
567
  # A meridian used to take longitude measurements from.
566
-
567
568
  class PrimeMeridian < Info
568
569
  def initialize(name, angular_unit, longitude, *optional) # :nodoc:
569
570
  super(name, *optional)
@@ -603,9 +604,9 @@ module RGeo
603
604
  # == OGC spec description
604
605
  #
605
606
  # An approximation of the Earth's surface as a squashed sphere.
606
-
607
607
  class Ellipsoid < Info
608
- def initialize(name, semi_major_axis, semi_minor_axis, inverse_flattening, ivf_definitive, linear_unit, *optional) # :nodoc:
608
+ def initialize(name, semi_major_axis, semi_minor_axis, inverse_flattening, ivf_definitive,
609
+ linear_unit, *optional) # :nodoc:
609
610
  super(name, *optional)
610
611
  @semi_major_axis = semi_major_axis.to_f
611
612
  @semi_minor_axis = semi_minor_axis.to_f
@@ -710,7 +711,6 @@ module RGeo
710
711
  # This is a non-instantiable abstract class. You must instantiate
711
712
  # one of the subclasses HorizontalDatum, VerticalDatum, or
712
713
  # LocalDatum.
713
-
714
714
  class Datum < Info
715
715
  def initialize(name, datum_type, *optional) # :nodoc:
716
716
  super(name, *optional)
@@ -730,7 +730,6 @@ module RGeo
730
730
  # == OGC spec description
731
731
  #
732
732
  # Procedure used to measure vertical distances.
733
-
734
733
  class VerticalDatum < Datum
735
734
  def wkt_typename
736
735
  "VERT_DATUM"
@@ -760,7 +759,6 @@ module RGeo
760
759
  # coordinates can be transformed between two different local
761
760
  # coordinate systems, as long as they are based on the same local
762
761
  # datum.
763
-
764
762
  class LocalDatum < Datum
765
763
  def wkt_typename
766
764
  "LOCAL_DATUM"
@@ -786,7 +784,6 @@ module RGeo
786
784
  # == OGC spec description
787
785
  #
788
786
  # Procedure used to measure positions on the surface of the Earth.
789
-
790
787
  class HorizontalDatum < Datum
791
788
  def initialize(name, datum_type, ellipsoid, wgs84_parameters, *optional) # :nodoc:
792
789
  super(name, datum_type, *optional)
@@ -820,8 +817,8 @@ module RGeo
820
817
  private
821
818
 
822
819
  def wkt_content(standard_brackets)
823
- array = [@ellipsoid.to_wkt(standard_brackets)]
824
- array << @wgs84_parameters.to_wkt(standard_brackets) if @wgs84_parameters
820
+ array = [@ellipsoid.to_wkt(standard_brackets: standard_brackets)]
821
+ array << @wgs84_parameters.to_wkt(standard_brackets: standard_brackets) if @wgs84_parameters
825
822
  array
826
823
  end
827
824
  end
@@ -829,7 +826,6 @@ module RGeo
829
826
  # == OGC spec description
830
827
  #
831
828
  # A projection from geographic coordinates to projected coordinates.
832
-
833
829
  class Projection < Info
834
830
  def initialize(name, class_name, parameters, *optional) # :nodoc:
835
831
  super(name, *optional)
@@ -908,7 +904,6 @@ module RGeo
908
904
  # GeographicCoordinateSystem, ProjectedCoordinateSystem,
909
905
  # VerticalCoordinateSystem, LocalCoordinateSystem, or
910
906
  # CompoundCoordinateSystem.
911
-
912
907
  class CoordinateSystem < Info
913
908
  def initialize(name, dimension, *optional) # :nodoc:
914
909
  super(name, *optional)
@@ -921,16 +916,61 @@ module RGeo
921
916
  # Gets axis details for dimension within coordinate system. Each
922
917
  # dimension in the coordinate system has a corresponding axis.
923
918
 
924
- def get_axis(dimension)
919
+ def get_axis(_dimension)
925
920
  nil
926
921
  end
927
922
 
928
923
  # Gets units for dimension within coordinate system. Each
929
924
  # dimension in the coordinate system has corresponding units.
930
925
 
931
- def get_units(dimension)
926
+ def get_units(_dimension)
932
927
  nil
933
928
  end
929
+
930
+ def geographic?
931
+ false
932
+ end
933
+
934
+ def projected?
935
+ false
936
+ end
937
+
938
+ def wkt_typename
939
+ "CS"
940
+ end
941
+
942
+ # Not an OGC method, but useful for being able to
943
+ # transform directly from a CoordinateSystem object.
944
+ def transform_coords(target_cs, x, y, z = nil)
945
+ ct = CoordinateTransform.create(self, target_cs)
946
+ ct.transform_coords(x, y, z)
947
+ end
948
+
949
+ class << self
950
+ def create(defn, dimension = 2, *optional)
951
+ # Need this so we can maintain consistency with actual
952
+ # CoordinateSystem implementations
953
+
954
+ if defn.is_a?(Integer)
955
+ # not technically correct but we can use cartesian as a placeholder
956
+ # to form valid wkt
957
+ defn_string = "Cartesian"
958
+ new(defn_string, dimension, "EPSG", defn, *optional)
959
+ else
960
+ new(defn, dimension, *optional)
961
+ end
962
+ end
963
+
964
+ def create_from_wkt(str)
965
+ CS.create_from_wkt(str)
966
+ end
967
+ end
968
+
969
+ private
970
+
971
+ def wkt_content(_)
972
+ [@dimension]
973
+ end
934
974
  end
935
975
 
936
976
  # == OGC spec description
@@ -940,7 +980,6 @@ module RGeo
940
980
  # as a geographic or a projected coordinate system with a horizontal
941
981
  # datum. The other is a vertical CRS which is a one-dimensional
942
982
  # coordinate system with a vertical datum.
943
-
944
983
  class CompoundCoordinateSystem < CoordinateSystem
945
984
  def initialize(name, head, tail, *optional) # :nodoc:
946
985
  super(name, head.dimension + tail.dimension, *optional)
@@ -985,7 +1024,7 @@ module RGeo
985
1024
  private
986
1025
 
987
1026
  def wkt_content(standard_brackets)
988
- [@head.to_wkt(standard_brackets), @tail.to_wkt(standard_brackets)]
1027
+ [@head.to_wkt(standard_brackets: standard_brackets), @tail.to_wkt(standard_brackets: standard_brackets)]
989
1028
  end
990
1029
  end
991
1030
 
@@ -1007,7 +1046,6 @@ module RGeo
1007
1046
  #
1008
1047
  # RGeo's implementation does not provide the Coordinate
1009
1048
  # Transformation (CT) package.
1010
-
1011
1049
  class LocalCoordinateSystem < CoordinateSystem
1012
1050
  def initialize(name, local_datum, unit, axes, *optional) # :nodoc:
1013
1051
  super(name, axes.size, *optional)
@@ -1027,7 +1065,7 @@ module RGeo
1027
1065
 
1028
1066
  # Implements CoordinateSystem#get_units
1029
1067
 
1030
- def get_units(index)
1068
+ def get_units(_index)
1031
1069
  @unit
1032
1070
  end
1033
1071
 
@@ -1050,9 +1088,9 @@ module RGeo
1050
1088
 
1051
1089
  def wkt_content(standard_brackets)
1052
1090
  [
1053
- @local_datum.to_wkt(standard_brackets),
1054
- @unit.to_wkt(standard_brackets)
1055
- ] + @axes.map { |ax| ax.to_wkt(standard_brackets) }
1091
+ @local_datum.to_wkt(standard_brackets: standard_brackets),
1092
+ @unit.to_wkt(standard_brackets: standard_brackets)
1093
+ ] + @axes.map { |ax| ax.to_wkt(standard_brackets: standard_brackets) }
1056
1094
  end
1057
1095
  end
1058
1096
 
@@ -1064,7 +1102,6 @@ module RGeo
1064
1102
  # the Z axis will point North, and the Y axis will point East (e.g.
1065
1103
  # a right handed system), but you should check the axes for
1066
1104
  # non-default values.
1067
-
1068
1105
  class GeocentricCoordinateSystem < CoordinateSystem
1069
1106
  def initialize(name, horizontal_datum, prime_meridian, linear_unit, axis0, axis1, axis2, *optional) # :nodoc:
1070
1107
  super(name, 3, *optional)
@@ -1090,7 +1127,7 @@ module RGeo
1090
1127
 
1091
1128
  # Implements CoordinateSystem#get_units
1092
1129
 
1093
- def get_units(index)
1130
+ def get_units(_index)
1094
1131
  @linear_unit
1095
1132
  end
1096
1133
 
@@ -1100,6 +1137,10 @@ module RGeo
1100
1137
  [@axis0, @axis1, @axis2][index]
1101
1138
  end
1102
1139
 
1140
+ def geographic?
1141
+ true
1142
+ end
1143
+
1103
1144
  def wkt_typename
1104
1145
  "GEOCCS"
1105
1146
  end
@@ -1120,13 +1161,13 @@ module RGeo
1120
1161
 
1121
1162
  def wkt_content(standard_brackets)
1122
1163
  arr = [
1123
- @horizontal_datum.to_wkt(standard_brackets),
1124
- @prime_meridian.to_wkt(standard_brackets),
1125
- @linear_unit.to_wkt(standard_brackets)
1164
+ @horizontal_datum.to_wkt(standard_brackets: standard_brackets),
1165
+ @prime_meridian.to_wkt(standard_brackets: standard_brackets),
1166
+ @linear_unit.to_wkt(standard_brackets: standard_brackets)
1126
1167
  ]
1127
- arr << @axis0.to_wkt(standard_brackets) if @axis0
1128
- arr << @axis1.to_wkt(standard_brackets) if @axis1
1129
- arr << @axis2.to_wkt(standard_brackets) if @axis2
1168
+ arr << @axis0.to_wkt(standard_brackets: standard_brackets) if @axis0
1169
+ arr << @axis1.to_wkt(standard_brackets: standard_brackets) if @axis1
1170
+ arr << @axis2.to_wkt(standard_brackets: standard_brackets) if @axis2
1130
1171
  arr
1131
1172
  end
1132
1173
  end
@@ -1135,7 +1176,6 @@ module RGeo
1135
1176
  #
1136
1177
  # A one-dimensional coordinate system suitable for vertical
1137
1178
  # measurements.
1138
-
1139
1179
  class VerticalCoordinateSystem < CoordinateSystem
1140
1180
  def initialize(name, vertical_datum, vertical_unit, axis, *optional) # :nodoc:
1141
1181
  super(name, 1, *optional)
@@ -1153,13 +1193,13 @@ module RGeo
1153
1193
 
1154
1194
  # Implements CoordinateSystem#get_units
1155
1195
 
1156
- def get_units(index)
1196
+ def get_units(_index)
1157
1197
  @vertical_unit
1158
1198
  end
1159
1199
 
1160
1200
  # Implements CoordinateSystem#get_axis
1161
1201
 
1162
- def get_axis(index)
1202
+ def get_axis(_index)
1163
1203
  @axis
1164
1204
  end
1165
1205
 
@@ -1181,8 +1221,11 @@ module RGeo
1181
1221
  private
1182
1222
 
1183
1223
  def wkt_content(standard_brackets)
1184
- arr = [@vertical_datum.to_wkt(standard_brackets), @vertical_unit.to_wkt(standard_brackets)]
1185
- arr << @axis.to_wkt(standard_brackets) if @axis
1224
+ arr = [
1225
+ @vertical_datum.to_wkt(standard_brackets: standard_brackets),
1226
+ @vertical_unit.to_wkt(standard_brackets: standard_brackets)
1227
+ ]
1228
+ arr << @axis.to_wkt(standard_brackets: standard_brackets) if @axis
1186
1229
  arr
1187
1230
  end
1188
1231
  end
@@ -1196,7 +1239,6 @@ module RGeo
1196
1239
  # This is a non-instantiable abstract class. You must instantiate
1197
1240
  # one of the subclasses GeographicCoordinateSystem or
1198
1241
  # ProjectedCoordinateSystem.
1199
-
1200
1242
  class HorizontalCoordinateSystem < CoordinateSystem
1201
1243
  def initialize(name, horizontal_datum, *optional) # :nodoc:
1202
1244
  super(name, 2, *optional)
@@ -1214,7 +1256,6 @@ module RGeo
1214
1256
  # You can find out which this is by examining the axes. You should
1215
1257
  # also check the angular units, since not all geographic coordinate
1216
1258
  # systems use degrees.
1217
-
1218
1259
  class GeographicCoordinateSystem < HorizontalCoordinateSystem
1219
1260
  def initialize(name, angular_unit, horizontal_datum, prime_meridian, axis0, axis1, *optional) # :nodoc:
1220
1261
  super(name, horizontal_datum, *optional)
@@ -1233,7 +1274,7 @@ module RGeo
1233
1274
 
1234
1275
  # Implements CoordinateSystem#get_units
1235
1276
 
1236
- def get_units(index)
1277
+ def get_units(_index)
1237
1278
  @angular_unit
1238
1279
  end
1239
1280
 
@@ -1255,10 +1296,14 @@ module RGeo
1255
1296
  # of interest. The first conversion (with index=0) should provide
1256
1297
  # acceptable accuracy over the largest possible area of interest.
1257
1298
 
1258
- def get_wgs84_conversion_info(index)
1299
+ def get_wgs84_conversion_info(_index)
1259
1300
  @horizontal_datum.wgs84_parameters
1260
1301
  end
1261
1302
 
1303
+ def geographic?
1304
+ true
1305
+ end
1306
+
1262
1307
  def wkt_typename
1263
1308
  "GEOGCS"
1264
1309
  end
@@ -1279,12 +1324,12 @@ module RGeo
1279
1324
 
1280
1325
  def wkt_content(standard_brackets)
1281
1326
  arr = [
1282
- @horizontal_datum.to_wkt(standard_brackets),
1283
- @prime_meridian.to_wkt(standard_brackets),
1284
- @angular_unit.to_wkt(standard_brackets)
1327
+ @horizontal_datum.to_wkt(standard_brackets: standard_brackets),
1328
+ @prime_meridian.to_wkt(standard_brackets: standard_brackets),
1329
+ @angular_unit.to_wkt(standard_brackets: standard_brackets)
1285
1330
  ]
1286
- arr << @axis0.to_wkt(standard_brackets) if @axis0
1287
- arr << @axis1.to_wkt(standard_brackets) if @axis1
1331
+ arr << @axis0.to_wkt(standard_brackets: standard_brackets) if @axis0
1332
+ arr << @axis1.to_wkt(standard_brackets: standard_brackets) if @axis1
1288
1333
  arr
1289
1334
  end
1290
1335
  end
@@ -1292,7 +1337,6 @@ module RGeo
1292
1337
  # == OGC spec description
1293
1338
  #
1294
1339
  # A 2D cartographic coordinate system.
1295
-
1296
1340
  class ProjectedCoordinateSystem < HorizontalCoordinateSystem
1297
1341
  def initialize(name, geographic_coordinate_system, projection, linear_unit, axis0, axis1, *optional) # :nodoc:
1298
1342
  super(name, geographic_coordinate_system.horizontal_datum, *optional)
@@ -1315,7 +1359,7 @@ module RGeo
1315
1359
 
1316
1360
  # Implements CoordinateSystem#get_units
1317
1361
 
1318
- def get_units(index)
1362
+ def get_units(_index)
1319
1363
  @linear_unit
1320
1364
  end
1321
1365
 
@@ -1325,6 +1369,10 @@ module RGeo
1325
1369
  index == 1 ? @axis1 : @axis0
1326
1370
  end
1327
1371
 
1372
+ def projected?
1373
+ true
1374
+ end
1375
+
1328
1376
  def wkt_typename
1329
1377
  "PROJCS"
1330
1378
  end
@@ -1344,14 +1392,166 @@ module RGeo
1344
1392
  private
1345
1393
 
1346
1394
  def wkt_content(standard_brackets)
1347
- arr = [@geographic_coordinate_system.to_wkt(standard_brackets), @projection.to_wkt(standard_brackets)]
1348
- @projection.each_parameter { |param| arr << param.to_wkt(standard_brackets) }
1349
- arr << @linear_unit.to_wkt(standard_brackets)
1350
- arr << @axis0.to_wkt(standard_brackets) if @axis0
1351
- arr << @axis1.to_wkt(standard_brackets) if @axis1
1395
+ arr = [
1396
+ @geographic_coordinate_system.to_wkt(standard_brackets: standard_brackets),
1397
+ @projection.to_wkt(standard_brackets: standard_brackets)
1398
+ ]
1399
+ @projection.each_parameter { |param| arr << param.to_wkt(standard_brackets: standard_brackets) }
1400
+ arr << @linear_unit.to_wkt(standard_brackets: standard_brackets)
1401
+ arr << @axis0.to_wkt(standard_brackets: standard_brackets) if @axis0
1402
+ arr << @axis1.to_wkt(standard_brackets: standard_brackets) if @axis1
1352
1403
  arr
1353
1404
  end
1354
1405
  end
1406
+
1407
+ # CoordinateTransform object. Note it is a combo of
1408
+ # CoordinateTransform and MathTransform as specified in
1409
+ # the OGC standard. This is just to simplify the model
1410
+ # and keep all functionality in this class.
1411
+ #
1412
+ # @see https://portal.ogc.org/files/?artifact_id=999 page 79
1413
+ class CoordinateTransform < Info
1414
+ # Initialize a new CoordinateTransform
1415
+ #
1416
+ # Note this class should not be used directly since it does not
1417
+ # implement any transformation logic. It merely defines
1418
+ # what methods actual implementations must use.
1419
+ #
1420
+ # @param [CoordinateSystem] source_cs
1421
+ # @param [CoordinateSystem] target_cs
1422
+ # @param [Array] optional any params for Info or Base
1423
+ # @return [CoordinateTransform]
1424
+ def initialize(source_cs, target_cs, *optional)
1425
+ super(optional)
1426
+ @source_cs = source_cs
1427
+ @target_cs = target_cs
1428
+ end
1429
+ attr_accessor :source_cs, :target_cs
1430
+
1431
+ # TODO: This changes depending on what type of conversion is done
1432
+ # and we can't know unless we implement the conversion ourselves.
1433
+ # We should delegate all of the wkt generation to the library
1434
+ # if possible.
1435
+ def wkt_typename
1436
+ "CONVERSION"
1437
+ end
1438
+
1439
+ def inspect
1440
+ "#<#{self.class}:0x#{object_id.to_s(16)} @source_cs=#{source_cs.to_wkt} @target_cs=#{target_cs.to_wkt}>"
1441
+ end
1442
+
1443
+ # Human readable description of domain in source coordinate system.
1444
+ #
1445
+ # @return [String]
1446
+ def area_of_use
1447
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1448
+ end
1449
+
1450
+ # Semantic type of transform. For example, a datum transformation or a coordinate conversion.
1451
+ #
1452
+ # @return [String]
1453
+ def transform_type
1454
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1455
+ end
1456
+
1457
+ # Dimension of the source_cs
1458
+ #
1459
+ # @return [Integer]
1460
+ def dim_source
1461
+ source_cs.dimension
1462
+ end
1463
+
1464
+ # Dimension of the target_cs
1465
+ #
1466
+ # @return [Integer]
1467
+ def dim_target
1468
+ target_cs.dimension
1469
+ end
1470
+
1471
+ # Tests whether this transform does not move any points
1472
+ #
1473
+ # @return [Boolean]
1474
+ def identity?
1475
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1476
+ end
1477
+
1478
+ # Gets flags classifying domain points within a convex hull. The supplied ordinates are interpreted
1479
+ # as a sequence of points, which generates a convex hull in the source space. Conceptually, each
1480
+ # of the (usually infinite) points inside the convex hull is then tested against the source domain.
1481
+ # The flags of all these tests are then combined. In practice, implementations of different
1482
+ # transforms will use different short-cuts to avoid doing an infinite number of tests.
1483
+ #
1484
+ # @param [Array<<Array<Integer>>] points in tuples of (x,y,z) with z being optional
1485
+ # @return [Array<Integer>] the domain_flags of the input points
1486
+ def domain_flags(points)
1487
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1488
+ end
1489
+
1490
+ # Gets transformed convex hull. The supplied ordinates are interpreted as a sequence of points,
1491
+ # which generates a convex hull in the source space. The returned sequence of ordinates
1492
+ # represents a convex hull in the output space. The number of output points will often be different
1493
+ # from the number of input points. Each of the input points should be inside the valid domain (this
1494
+ # can be checked by testing the points' domain flags individually). However, the convex hull of the
1495
+ # input points may go outside the valid domain. The returned convex hull should contain the
1496
+ # transformed image of the intersection of the source convex hull and the source domain.
1497
+ #
1498
+ # @param [Array<<Array<Integer>>] points in tuples of (x,y,z) with z being optional
1499
+ # @return [Array<<Array<Integer>>]
1500
+ def codomain_convex_hull(points)
1501
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1502
+ end
1503
+
1504
+ # Transforms a coordinate point. The passed parameter point should not be modified.
1505
+ #
1506
+ # @param [Integer] x
1507
+ # @param [Integer] y
1508
+ # @param [Integer] z optional
1509
+ # @return [Array<Integer>] transformed point coordinates in (x,y,z) order
1510
+ def transform_coords(x, y, z = nil)
1511
+ raise NotImplementedError, "#{__method__} is not implemented in the abstract CoordinateTransform class."
1512
+ end
1513
+
1514
+ # Transforms a coordinate point. The passed parameter point should not be modified.
1515
+ #
1516
+ # @param [Array<Array<Integer>>] points in (x,y,z) tuples where z is optional
1517
+ # @return [Array<Array<Integer>>] list of transformed point coordinates in (x,y,z) order
1518
+ def transform_list(points)
1519
+ points.map { |x, y, z| transform_coords(x, y, z) }
1520
+ end
1521
+
1522
+ # Creates the inverse transform of this object. This method may fail if the transform is not one to
1523
+ # one. However, all cartographic projections should succeed.
1524
+ #
1525
+ # @return [CoordinateTransform]
1526
+ def inverse
1527
+ self.class.create(target_cs, source_cs)
1528
+ end
1529
+
1530
+ class << self
1531
+ # Initialize a new CoordinateTransform
1532
+ #
1533
+ # Note this class should not be used directly since it does not
1534
+ # implement any transformation logic. It merely defines
1535
+ # what methods actual implementations must use.
1536
+ #
1537
+ # @param [CoordinateSystem] source_cs
1538
+ # @param [CoordinateSystem] target_cs
1539
+ # @param [Array] optional any params for Info or Base
1540
+ # @return [CoordinateTransform]
1541
+ def create(source_cs, target_cs, *optional)
1542
+ new(source_cs, target_cs, optional)
1543
+ end
1544
+ end
1545
+
1546
+ private
1547
+
1548
+ def wkt_content(standard_brackets)
1549
+ source_cs_wkt = "SOURCECS[#{source_cs.to_wkt(standard_brackets: standard_brackets)}]"
1550
+ target_cs_wkt = "TARGETCS[#{target_cs.to_wkt(standard_brackets: standard_brackets)}]"
1551
+
1552
+ [source_cs_wkt, target_cs_wkt]
1553
+ end
1554
+ end
1355
1555
  end
1356
1556
  end
1357
1557
  end