rgeo-dschee 0.5.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +29 -0
- data/ext/geos_c_impl/coordinates.c +65 -0
- data/ext/geos_c_impl/coordinates.h +2 -0
- data/ext/geos_c_impl/extconf.rb +43 -0
- data/ext/geos_c_impl/factory.c +995 -0
- data/ext/geos_c_impl/factory.h +238 -0
- data/ext/geos_c_impl/geometry.c +1093 -0
- data/ext/geos_c_impl/geometry.h +23 -0
- data/ext/geos_c_impl/geometry_collection.c +757 -0
- data/ext/geos_c_impl/geometry_collection.h +46 -0
- data/ext/geos_c_impl/line_string.c +675 -0
- data/ext/geos_c_impl/line_string.h +32 -0
- data/ext/geos_c_impl/main.c +40 -0
- data/ext/geos_c_impl/point.c +236 -0
- data/ext/geos_c_impl/point.h +30 -0
- data/ext/geos_c_impl/polygon.c +359 -0
- data/ext/geos_c_impl/polygon.h +43 -0
- data/ext/geos_c_impl/preface.h +38 -0
- data/ext/proj4_c_impl/extconf.rb +62 -0
- data/ext/proj4_c_impl/main.c +315 -0
- data/lib/rgeo.rb +89 -0
- data/lib/rgeo/cartesian.rb +25 -0
- data/lib/rgeo/cartesian/analysis.rb +77 -0
- data/lib/rgeo/cartesian/bounding_box.rb +398 -0
- data/lib/rgeo/cartesian/calculations.rb +113 -0
- data/lib/rgeo/cartesian/factory.rb +347 -0
- data/lib/rgeo/cartesian/feature_classes.rb +100 -0
- data/lib/rgeo/cartesian/feature_methods.rb +88 -0
- data/lib/rgeo/cartesian/interface.rb +135 -0
- data/lib/rgeo/coord_sys.rb +43 -0
- data/lib/rgeo/coord_sys/cs/entities.rb +1315 -0
- data/lib/rgeo/coord_sys/cs/factories.rb +148 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +272 -0
- data/lib/rgeo/coord_sys/proj4.rb +293 -0
- data/lib/rgeo/coord_sys/srs_database/interface.rb +115 -0
- data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +140 -0
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +62 -0
- data/lib/rgeo/coord_sys/srs_database/url_reader.rb +63 -0
- data/lib/rgeo/error.rb +27 -0
- data/lib/rgeo/feature.rb +54 -0
- data/lib/rgeo/feature/curve.rb +111 -0
- data/lib/rgeo/feature/factory.rb +278 -0
- data/lib/rgeo/feature/factory_generator.rb +96 -0
- data/lib/rgeo/feature/geometry.rb +624 -0
- data/lib/rgeo/feature/geometry_collection.rb +95 -0
- data/lib/rgeo/feature/line.rb +26 -0
- data/lib/rgeo/feature/line_string.rb +60 -0
- data/lib/rgeo/feature/linear_ring.rb +26 -0
- data/lib/rgeo/feature/mixins.rb +143 -0
- data/lib/rgeo/feature/multi_curve.rb +71 -0
- data/lib/rgeo/feature/multi_line_string.rb +26 -0
- data/lib/rgeo/feature/multi_point.rb +33 -0
- data/lib/rgeo/feature/multi_polygon.rb +57 -0
- data/lib/rgeo/feature/multi_surface.rb +73 -0
- data/lib/rgeo/feature/point.rb +84 -0
- data/lib/rgeo/feature/polygon.rb +97 -0
- data/lib/rgeo/feature/surface.rb +79 -0
- data/lib/rgeo/feature/types.rb +284 -0
- data/lib/rgeo/geographic.rb +40 -0
- data/lib/rgeo/geographic/factory.rb +450 -0
- data/lib/rgeo/geographic/interface.rb +489 -0
- data/lib/rgeo/geographic/proj4_projector.rb +58 -0
- data/lib/rgeo/geographic/projected_feature_classes.rb +107 -0
- data/lib/rgeo/geographic/projected_feature_methods.rb +212 -0
- data/lib/rgeo/geographic/projected_window.rb +383 -0
- data/lib/rgeo/geographic/simple_mercator_projector.rb +110 -0
- data/lib/rgeo/geographic/spherical_feature_classes.rb +100 -0
- data/lib/rgeo/geographic/spherical_feature_methods.rb +134 -0
- data/lib/rgeo/geographic/spherical_math.rb +188 -0
- data/lib/rgeo/geos.rb +89 -0
- data/lib/rgeo/geos/capi_factory.rb +470 -0
- data/lib/rgeo/geos/capi_feature_classes.rb +129 -0
- data/lib/rgeo/geos/ffi_factory.rb +592 -0
- data/lib/rgeo/geos/ffi_feature_classes.rb +83 -0
- data/lib/rgeo/geos/ffi_feature_methods.rb +574 -0
- data/lib/rgeo/geos/interface.rb +202 -0
- data/lib/rgeo/geos/utils.rb +74 -0
- data/lib/rgeo/geos/zm_factory.rb +405 -0
- data/lib/rgeo/geos/zm_feature_classes.rb +80 -0
- data/lib/rgeo/geos/zm_feature_methods.rb +344 -0
- data/lib/rgeo/impl_helper.rb +19 -0
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +185 -0
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +61 -0
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +146 -0
- data/lib/rgeo/impl_helper/basic_point_methods.rb +104 -0
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +87 -0
- data/lib/rgeo/impl_helper/math.rb +14 -0
- data/lib/rgeo/impl_helper/utils.rb +29 -0
- data/lib/rgeo/version.rb +3 -0
- data/lib/rgeo/wkrep.rb +37 -0
- data/lib/rgeo/wkrep/wkb_generator.rb +201 -0
- data/lib/rgeo/wkrep/wkb_parser.rb +251 -0
- data/lib/rgeo/wkrep/wkt_generator.rb +207 -0
- data/lib/rgeo/wkrep/wkt_parser.rb +415 -0
- data/lib/rgeo/yaml.rb +23 -0
- data/test/cartesian_analysis_test.rb +65 -0
- data/test/cartesian_bbox_test.rb +123 -0
- data/test/common/factory_tests.rb +78 -0
- data/test/common/geometry_collection_tests.rb +237 -0
- data/test/common/line_string_tests.rb +330 -0
- data/test/common/multi_line_string_tests.rb +182 -0
- data/test/common/multi_point_tests.rb +200 -0
- data/test/common/multi_polygon_tests.rb +191 -0
- data/test/common/point_tests.rb +370 -0
- data/test/common/polygon_tests.rb +261 -0
- data/test/coord_sys/ogc_cs_test.rb +342 -0
- data/test/coord_sys/proj4_srs_data_test.rb +41 -0
- data/test/coord_sys/proj4_test.rb +150 -0
- data/test/coord_sys/sr_org_test.rb +32 -0
- data/test/coord_sys/url_reader_test.rb +42 -0
- data/test/geos_capi/factory_test.rb +31 -0
- data/test/geos_capi/geometry_collection_test.rb +24 -0
- data/test/geos_capi/line_string_test.rb +24 -0
- data/test/geos_capi/misc_test.rb +116 -0
- data/test/geos_capi/multi_line_string_test.rb +24 -0
- data/test/geos_capi/multi_point_test.rb +24 -0
- data/test/geos_capi/multi_polygon_test.rb +39 -0
- data/test/geos_capi/parsing_unparsing_test.rb +40 -0
- data/test/geos_capi/point_test.rb +72 -0
- data/test/geos_capi/polygon_test.rb +154 -0
- data/test/geos_capi/zmfactory_test.rb +57 -0
- data/test/geos_ffi/factory_test.rb +31 -0
- data/test/geos_ffi/geometry_collection_test.rb +24 -0
- data/test/geos_ffi/line_string_test.rb +24 -0
- data/test/geos_ffi/misc_test.rb +63 -0
- data/test/geos_ffi/multi_line_string_test.rb +24 -0
- data/test/geos_ffi/multi_point_test.rb +24 -0
- data/test/geos_ffi/multi_polygon_test.rb +33 -0
- data/test/geos_ffi/parsing_unparsing_test.rb +41 -0
- data/test/geos_ffi/point_test.rb +77 -0
- data/test/geos_ffi/polygon_test.rb +46 -0
- data/test/geos_ffi/zmfactory_test.rb +58 -0
- data/test/mixins_test.rb +141 -0
- data/test/oneoff_test.rb +26 -0
- data/test/projected_geographic/factory_test.rb +25 -0
- data/test/projected_geographic/geometry_collection_test.rb +24 -0
- data/test/projected_geographic/line_string_test.rb +24 -0
- data/test/projected_geographic/multi_line_string_test.rb +26 -0
- data/test/projected_geographic/multi_point_test.rb +30 -0
- data/test/projected_geographic/multi_polygon_test.rb +25 -0
- data/test/projected_geographic/point_test.rb +51 -0
- data/test/projected_geographic/polygon_test.rb +24 -0
- data/test/simple_cartesian/calculations_test.rb +99 -0
- data/test/simple_cartesian/factory_test.rb +27 -0
- data/test/simple_cartesian/geometry_collection_test.rb +30 -0
- data/test/simple_cartesian/line_string_test.rb +31 -0
- data/test/simple_cartesian/multi_line_string_test.rb +28 -0
- data/test/simple_cartesian/multi_point_test.rb +31 -0
- data/test/simple_cartesian/multi_polygon_test.rb +31 -0
- data/test/simple_cartesian/point_test.rb +50 -0
- data/test/simple_cartesian/polygon_test.rb +28 -0
- data/test/simple_mercator/factory_test.rb +25 -0
- data/test/simple_mercator/geometry_collection_test.rb +24 -0
- data/test/simple_mercator/line_string_test.rb +24 -0
- data/test/simple_mercator/multi_line_string_test.rb +26 -0
- data/test/simple_mercator/multi_point_test.rb +29 -0
- data/test/simple_mercator/multi_polygon_test.rb +25 -0
- data/test/simple_mercator/point_test.rb +55 -0
- data/test/simple_mercator/polygon_test.rb +24 -0
- data/test/simple_mercator/window_test.rb +173 -0
- data/test/spherical_geographic/calculations_test.rb +167 -0
- data/test/spherical_geographic/factory_test.rb +27 -0
- data/test/spherical_geographic/geometry_collection_test.rb +31 -0
- data/test/spherical_geographic/line_string_test.rb +31 -0
- data/test/spherical_geographic/multi_line_string_test.rb +29 -0
- data/test/spherical_geographic/multi_point_test.rb +31 -0
- data/test/spherical_geographic/multi_polygon_test.rb +31 -0
- data/test/spherical_geographic/point_test.rb +78 -0
- data/test/spherical_geographic/polygon_test.rb +28 -0
- data/test/types_test.rb +42 -0
- data/test/wkrep/wkb_generator_test.rb +185 -0
- data/test/wkrep/wkb_parser_test.rb +293 -0
- data/test/wkrep/wkt_generator_test.rb +294 -0
- data/test/wkrep/wkt_parser_test.rb +412 -0
- metadata +386 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
#
|
|
3
|
+
# OGC CS factory for RGeo
|
|
4
|
+
#
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
module RGeo
|
|
8
|
+
module CoordSys
|
|
9
|
+
# This module contains an implementation of the CS (coordinate
|
|
10
|
+
# systems) package of the OGC Coordinate Transform spec. It provides
|
|
11
|
+
# classes for representing ellipsoids, datums, coordinate systems,
|
|
12
|
+
# and other related concepts, as well as a parser for the WKT format
|
|
13
|
+
# for specifying coordinate systems.
|
|
14
|
+
#
|
|
15
|
+
# Generally, the easiest way to create coordinate system objects is
|
|
16
|
+
# to use RGeo::CoordSys::CS.create_from_wkt, which parses the WKT
|
|
17
|
+
# format. You can also use the create methods available for each
|
|
18
|
+
# object class.
|
|
19
|
+
#
|
|
20
|
+
# Most but not all of the spec is implemented here.
|
|
21
|
+
# Currently missing are:
|
|
22
|
+
#
|
|
23
|
+
# * XML format is not implemented. We're assuming that WKT is the
|
|
24
|
+
# preferred format.
|
|
25
|
+
# * The PT and CT packages are not implemented.
|
|
26
|
+
# * FittedCoordinateSystem is not implemented.
|
|
27
|
+
# * The defaultEnvelope attribute of CS_CoordinateSystem is not
|
|
28
|
+
# implemented.
|
|
29
|
+
|
|
30
|
+
module CS
|
|
31
|
+
# A class implementing the CS_CoordinateSystemFactory interface.
|
|
32
|
+
# It provides methods for building up complex objects from simpler
|
|
33
|
+
# objects or values.
|
|
34
|
+
#
|
|
35
|
+
# Note that the methods of CS_CoordinateSystemFactory do not provide
|
|
36
|
+
# facilities for setting the authority. If you need to set authority
|
|
37
|
+
# values, use the create methods for the object classes themselves.
|
|
38
|
+
|
|
39
|
+
class CoordinateSystemFactory
|
|
40
|
+
# Create a CompoundCoordinateSystem from a name, and two
|
|
41
|
+
# constituent coordinate systems.
|
|
42
|
+
|
|
43
|
+
def create_compound_coordinate_system(name_, head_, tail_)
|
|
44
|
+
CompoundCoordinateSystem.create(name_, head_, tail_)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Create an Ellipsoid from a name, semi-major axis, and semi-minor
|
|
48
|
+
# axis. You can also provide a LinearUnit, but this is optional
|
|
49
|
+
# and may be set to nil.
|
|
50
|
+
|
|
51
|
+
def create_ellipsoid(name_, semi_major_axis_, semi_minor_axis_, linear_unit_)
|
|
52
|
+
Ellipsoid.create_ellipsoid(name_, semi_major_axis_, semi_minor_axis_, linear_unit_)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Create an Ellipsoid from a name, semi-major axis, and an inverse
|
|
56
|
+
# flattening factor. You can also provide a LinearUnit, but this
|
|
57
|
+
# is optional and may be set to nil.
|
|
58
|
+
|
|
59
|
+
def create_flattened_sphere(name_, semi_major_axis_, inverse_flattening_, linear_unit_)
|
|
60
|
+
Ellipsoid.create_flattened_sphere(name_, semi_major_axis_, inverse_flattening_, linear_unit_)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Create any object given the OGC WKT format. Raises
|
|
64
|
+
# Error::ParseError if a syntax error is encounterred.
|
|
65
|
+
|
|
66
|
+
def create_from_wkt(str_)
|
|
67
|
+
WKTParser.new(str_).parse
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Create a GeographicCoordinateSystem, given a name, an
|
|
71
|
+
# AngularUnit, a HorizontalDatum, a PrimeMeridian, and two
|
|
72
|
+
# AxisInfo objects. The AxisInfo objects are optional and may be
|
|
73
|
+
# set to nil.
|
|
74
|
+
|
|
75
|
+
def create_geographic_coordinate_system(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_)
|
|
76
|
+
GeographicCoordinateSystem.create(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Create a HorizontalDatum given a name, a horizontal datum type
|
|
80
|
+
# code, an Ellipsoid, and a WGS84ConversionInfo. The
|
|
81
|
+
# WGS84ConversionInfo is optional and may be set to nil.
|
|
82
|
+
|
|
83
|
+
def create_horizontal_datum(name_, horizontal_datum_type_, ellipsoid_, to_wgs84_)
|
|
84
|
+
HorizontalDatum.create(name_, horizontal_datum_type_, ellipsoid_, to_wgs84_)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Create a LocalCoordinateSystem given a name, a LocalDatum, a
|
|
88
|
+
# Unit, and an array of at least one AxisInfo.
|
|
89
|
+
|
|
90
|
+
def create_local_coordinate_system(name_, datum_, unit_, axes_)
|
|
91
|
+
LocalCoordinateSystem.create(name_, datum_, unit_, axes_)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Create a LocalDatum given a name and a local datum type code.
|
|
95
|
+
|
|
96
|
+
def create_local_datum(_name_, local_datum_type_)
|
|
97
|
+
LocalDatum.create(name, local_datum_type_)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Create a PrimeMeridian given a name, an AngularUnit, and a
|
|
101
|
+
# longitude offset.
|
|
102
|
+
|
|
103
|
+
def create_prime_meridian(_name_, angular_unit_, longitude_)
|
|
104
|
+
PrimeMeridian.create(name, angular_unit_, longitude_)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Create a ProjectedCoordinateSystem given a name, a
|
|
108
|
+
# GeographicCoordinateSystem, and Projection, a LinearUnit, and
|
|
109
|
+
# two AxisInfo objects. The AxisInfo objects are optional and may
|
|
110
|
+
# be set to nil.
|
|
111
|
+
|
|
112
|
+
def create_projected_coordinate_system(name_, gcs_, projection_, linear_unit_, axis0_, axis1_)
|
|
113
|
+
ProjectedCoordinateSystem.create(name_, gcs_, projection_, linear_unit_, axis0_, axis1_)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Create a Projection given a name, a projection class, and an
|
|
117
|
+
# array of ProjectionParameter.
|
|
118
|
+
|
|
119
|
+
def create_projection(name_, wkt_projection_class_, parameters_)
|
|
120
|
+
Projection.create(name_, wkt_projection_class_, parameters_)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Create a VerticalCoordinateSystem given a name, a VerticalDatum,
|
|
124
|
+
# a VerticalUnit, and an AxisInfo. The AxisInfo is optional and
|
|
125
|
+
# may be nil.
|
|
126
|
+
|
|
127
|
+
def create_vertical_coordinate_system(name_, vertical_datum_, vertical_unit_, axis_)
|
|
128
|
+
VerticalCoordinateSystem.create(name_, vertical_datum_, vertical_unit_, axis_)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Create a VerticalDatum given a name ane a datum type code.
|
|
132
|
+
|
|
133
|
+
def create_vertical_datum(name_, vertical_datum_type_)
|
|
134
|
+
VerticalDatum.create(name_, vertical_datum_type_)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class << self
|
|
139
|
+
# Parsees OGC WKT format and returns the object created. Raises
|
|
140
|
+
# Error::ParseError if a syntax error is encounterred.
|
|
141
|
+
|
|
142
|
+
def create_from_wkt(str_)
|
|
143
|
+
WKTParser.new(str_).parse
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
#
|
|
3
|
+
# OGC CS wkt parser for RGeo
|
|
4
|
+
#
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
module RGeo
|
|
8
|
+
module CoordSys
|
|
9
|
+
module CS
|
|
10
|
+
class WKTParser # :nodoc:
|
|
11
|
+
def initialize(str_)
|
|
12
|
+
@scanner = ::StringScanner.new(str_)
|
|
13
|
+
next_token
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse(containing_type_ = nil) # :nodoc:
|
|
17
|
+
if @cur_token.is_a?(QuotedString) ||
|
|
18
|
+
@cur_token.is_a?(::Numeric) ||
|
|
19
|
+
(containing_type_ == "AXIS" && @cur_token.is_a?(TypeString))
|
|
20
|
+
value_ = @cur_token
|
|
21
|
+
next_token
|
|
22
|
+
return value_
|
|
23
|
+
end
|
|
24
|
+
unless @cur_token.is_a?(TypeString)
|
|
25
|
+
raise Error::ParseError("Found token #{@cur_token} when we expected a value")
|
|
26
|
+
end
|
|
27
|
+
type_ = @cur_token
|
|
28
|
+
next_token
|
|
29
|
+
consume_token_type(:begin)
|
|
30
|
+
args_ = ArgumentList.new
|
|
31
|
+
args_ << parse(type_)
|
|
32
|
+
loop do
|
|
33
|
+
break unless @cur_token == :comma
|
|
34
|
+
next_token
|
|
35
|
+
args_ << parse(type_)
|
|
36
|
+
end
|
|
37
|
+
consume_token_type(:end)
|
|
38
|
+
obj_ = nil
|
|
39
|
+
case type_
|
|
40
|
+
when "AUTHORITY"
|
|
41
|
+
obj_ = AuthorityClause.new(args_.shift(QuotedString), args_.shift(QuotedString))
|
|
42
|
+
when "EXTENSION"
|
|
43
|
+
obj_ = ExtensionClause.new(args_.shift(QuotedString), args_.shift(QuotedString))
|
|
44
|
+
when "AXIS"
|
|
45
|
+
obj_ = AxisInfo.create(args_.shift(QuotedString), args_.shift(TypeString))
|
|
46
|
+
when "TOWGS84"
|
|
47
|
+
bursa_wolf_params_ = args_.find_all(::Numeric)
|
|
48
|
+
unless bursa_wolf_params_.size == 7
|
|
49
|
+
raise Error::ParseError("Expected 7 Bursa Wolf parameters but found #{bursa_wolf_params_.size}")
|
|
50
|
+
end
|
|
51
|
+
obj_ = WGS84ConversionInfo.create(*bursa_wolf_params_)
|
|
52
|
+
when "UNIT"
|
|
53
|
+
case containing_type_
|
|
54
|
+
when "GEOCCS", "VERT_CS", "PROJCS", "SPHEROID"
|
|
55
|
+
klass_ = LinearUnit
|
|
56
|
+
when "GEOGCS"
|
|
57
|
+
klass_ = AngularUnit
|
|
58
|
+
else
|
|
59
|
+
klass_ = Unit
|
|
60
|
+
end
|
|
61
|
+
obj_ = klass_.create(args_.shift(QuotedString), args_.shift(::Numeric), *args_.create_optionals)
|
|
62
|
+
when "PARAMETER"
|
|
63
|
+
obj_ = ProjectionParameter.create(args_.shift(QuotedString), args_.shift(::Numeric))
|
|
64
|
+
when "PRIMEM"
|
|
65
|
+
obj_ = PrimeMeridian.create(args_.shift(QuotedString), nil, args_.shift(::Numeric), *args_.create_optionals)
|
|
66
|
+
when "SPHEROID"
|
|
67
|
+
obj_ = Ellipsoid.create_flattened_sphere(args_.shift(QuotedString), args_.shift(::Numeric), args_.shift(::Numeric), args_.find_first(LinearUnit), *args_.create_optionals)
|
|
68
|
+
when "PROJECTION"
|
|
69
|
+
name_ = args_.shift(QuotedString)
|
|
70
|
+
obj_ = Projection.create(name_, name_, args_.find_all(ProjectionParameter), *args_.create_optionals)
|
|
71
|
+
when "DATUM"
|
|
72
|
+
name_ = args_.shift(QuotedString)
|
|
73
|
+
ellipsoid_ = args_.find_first(Ellipsoid)
|
|
74
|
+
to_wgs84_ = args_.find_first(WGS84ConversionInfo)
|
|
75
|
+
obj_ = HorizontalDatum.create(name_, HD_GEOCENTRIC, ellipsoid_, to_wgs84_, *args_.create_optionals)
|
|
76
|
+
when "VERT_DATUM"
|
|
77
|
+
obj_ = VerticalDatum.create(args_.shift(QuotedString), args_.shift(::Numeric), *args_.create_optionals)
|
|
78
|
+
when "LOCAL_DATUM"
|
|
79
|
+
obj_ = LocalDatum.create(args_.shift(QuotedString), args_.shift(::Numeric), *args_.create_optionals)
|
|
80
|
+
when "COMPD_CS"
|
|
81
|
+
obj_ = CompoundCoordinateSystem.create(args_.shift(QuotedString), args_.shift(CoordinateSystem), args_.shift(CoordinateSystem), *args_.create_optionals)
|
|
82
|
+
when "LOCAL_CS"
|
|
83
|
+
name_ = args_.shift(QuotedString)
|
|
84
|
+
local_datum_ = args_.find_first(LocalDatum)
|
|
85
|
+
unit_ = args_.find_first(Unit)
|
|
86
|
+
axes_ = args_.find_all(AxisInfo)
|
|
87
|
+
unless axes_.size > 0
|
|
88
|
+
raise Error::ParseError("Expected at least one AXIS in a LOCAL_CS")
|
|
89
|
+
end
|
|
90
|
+
obj_ = LocalCoordinateSystem.create(name_, local_datum_, unit_, axes_, *args_.create_optionals)
|
|
91
|
+
when "GEOCCS"
|
|
92
|
+
name_ = args_.shift(QuotedString)
|
|
93
|
+
horizontal_datum_ = args_.find_first(HorizontalDatum)
|
|
94
|
+
prime_meridian_ = args_.find_first(PrimeMeridian)
|
|
95
|
+
linear_unit_ = args_.find_first(LinearUnit)
|
|
96
|
+
axes_ = args_.find_all(AxisInfo)
|
|
97
|
+
unless axes_.size == 0 || axes_.size == 3
|
|
98
|
+
raise Error::ParseError("GEOCCS must contain either 0 or 3 AXIS parameters")
|
|
99
|
+
end
|
|
100
|
+
obj_ = GeocentricCoordinateSystem.create(name_, horizontal_datum_, prime_meridian_, linear_unit_, axes_[0], axes_[1], axes_[2], *args_.create_optionals)
|
|
101
|
+
when "VERT_CS"
|
|
102
|
+
name_ = args_.shift(QuotedString)
|
|
103
|
+
vertical_datum_ = args_.find_first(VerticalDatum)
|
|
104
|
+
linear_unit_ = args_.find_first(LinearUnit)
|
|
105
|
+
axis_ = args_.find_first(AxisInfo)
|
|
106
|
+
obj_ = VerticalCoordinateSystem.create(name_, vertical_datum_, linear_unit_, axis_, *args_.create_optionals)
|
|
107
|
+
when "GEOGCS"
|
|
108
|
+
name_ = args_.shift(QuotedString)
|
|
109
|
+
horizontal_datum_ = args_.find_first(HorizontalDatum)
|
|
110
|
+
prime_meridian_ = args_.find_first(PrimeMeridian)
|
|
111
|
+
angular_unit_ = args_.find_first(AngularUnit)
|
|
112
|
+
axes_ = args_.find_all(AxisInfo)
|
|
113
|
+
unless axes_.size == 0 || axes_.size == 2
|
|
114
|
+
raise Error::ParseError("GEOGCS must contain either 0 or 2 AXIS parameters")
|
|
115
|
+
end
|
|
116
|
+
obj_ = GeographicCoordinateSystem.create(name_, angular_unit_, horizontal_datum_, prime_meridian_, axes_[0], axes_[1], *args_.create_optionals)
|
|
117
|
+
when "PROJCS"
|
|
118
|
+
name_ = args_.shift(QuotedString)
|
|
119
|
+
geographic_coordinate_system_ = args_.find_first(GeographicCoordinateSystem)
|
|
120
|
+
projection_ = args_.find_first(Projection)
|
|
121
|
+
parameters_ = args_.find_all(ProjectionParameter)
|
|
122
|
+
projection_.instance_variable_get(:@parameters).concat(parameters_)
|
|
123
|
+
linear_unit_ = args_.find_first(LinearUnit)
|
|
124
|
+
axes_ = args_.find_all(AxisInfo)
|
|
125
|
+
unless axes_.size == 0 || axes_.size == 2
|
|
126
|
+
raise Error::ParseError("PROJCS must contain either 0 or 2 AXIS parameters")
|
|
127
|
+
end
|
|
128
|
+
obj_ = ProjectedCoordinateSystem.create(name_, geographic_coordinate_system_, projection_, linear_unit_, axes_[0], axes_[1], *args_.create_optionals)
|
|
129
|
+
else
|
|
130
|
+
raise Error::ParseError, "Unrecognized type: #{type_}"
|
|
131
|
+
end
|
|
132
|
+
args_.assert_empty
|
|
133
|
+
obj_
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def consume_token_type(type_) # :nodoc:
|
|
137
|
+
expect_token_type(type_)
|
|
138
|
+
tok_ = @cur_token
|
|
139
|
+
next_token
|
|
140
|
+
tok_
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def expect_token_type(type_) # :nodoc:
|
|
144
|
+
unless type_ === @cur_token
|
|
145
|
+
raise Error::ParseError, "#{type_.inspect} expected but #{@cur_token.inspect} found."
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def next_token # :nodoc:
|
|
150
|
+
@scanner.skip(/\s+/)
|
|
151
|
+
case @scanner.peek(1)
|
|
152
|
+
when '"'
|
|
153
|
+
@scanner.getch
|
|
154
|
+
@cur_token = QuotedString.new(@scanner.scan(/[^"]*/))
|
|
155
|
+
@scanner.getch
|
|
156
|
+
when ","
|
|
157
|
+
@scanner.getch
|
|
158
|
+
@cur_token = :comma
|
|
159
|
+
when "(", "["
|
|
160
|
+
@scanner.getch
|
|
161
|
+
@cur_token = :begin
|
|
162
|
+
when "]", ")"
|
|
163
|
+
@scanner.getch
|
|
164
|
+
@cur_token = :end
|
|
165
|
+
when /[a-zA-Z]/
|
|
166
|
+
@cur_token = TypeString.new(@scanner.scan(/[a-zA-Z]\w*/))
|
|
167
|
+
when "", nil
|
|
168
|
+
@cur_token = nil
|
|
169
|
+
else
|
|
170
|
+
@scanner.scan_until(/[^\s\(\)\[\],"]+/)
|
|
171
|
+
token_ = @scanner.matched
|
|
172
|
+
if token_ =~ /^[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?$/
|
|
173
|
+
@cur_token = token_.to_f
|
|
174
|
+
else
|
|
175
|
+
raise Error::ParseError, "Bad token: #{token_.inspect}"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
@cur_token
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
attr_reader :cur_token
|
|
182
|
+
|
|
183
|
+
class QuotedString < ::String # :nodoc:
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class TypeString < ::String # :nodoc:
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
class AuthorityClause # :nodoc:
|
|
190
|
+
def initialize(name_, code_) # :nodoc:
|
|
191
|
+
@name = name_
|
|
192
|
+
@code = code_
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def to_a # :nodoc:
|
|
196
|
+
[@name, @code]
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
class ExtensionClause # :nodoc:
|
|
201
|
+
def initialize(key_, value_) # :nodoc:
|
|
202
|
+
@key = key_
|
|
203
|
+
@value = value_
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
attr_reader :key # :nodoc:
|
|
207
|
+
attr_reader :value # :nodoc:
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class ArgumentList # :nodoc:
|
|
211
|
+
def initialize # :nodoc:
|
|
212
|
+
@values = []
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def <<(value_) # :nodoc:
|
|
216
|
+
@values << value_
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def assert_empty # :nodoc:
|
|
220
|
+
if @values.size > 0
|
|
221
|
+
names_ = @values.map do |val_|
|
|
222
|
+
val_.is_a?(Base) ? val_._wkt_typename : val_.inspect
|
|
223
|
+
end
|
|
224
|
+
raise Error::ParseError, "#{@values.size} unexpected arguments: #{names_.join(', ')}"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def find_first(klass_) # :nodoc:
|
|
229
|
+
@values.each_with_index do |val_, index_|
|
|
230
|
+
if val_.is_a?(klass_)
|
|
231
|
+
@values.slice!(index_)
|
|
232
|
+
return val_
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
nil
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def find_all(klass_) # :nodoc:
|
|
239
|
+
results_ = []
|
|
240
|
+
nvalues_ = []
|
|
241
|
+
@values.each do |val_|
|
|
242
|
+
if val_.is_a?(klass_)
|
|
243
|
+
results_ << val_
|
|
244
|
+
else
|
|
245
|
+
nvalues_ << val_
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
@values = nvalues_
|
|
249
|
+
results_
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def create_optionals # :nodoc:
|
|
253
|
+
hash_ = {}
|
|
254
|
+
find_all(ExtensionClause).each { |ec_| hash_[ec_.key] = ec_.value }
|
|
255
|
+
(find_first(AuthorityClause) || [nil, nil]).to_a + [nil, nil, nil, hash_]
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def shift(klass_ = nil) # :nodoc:
|
|
259
|
+
val_ = @values.shift
|
|
260
|
+
unless val_
|
|
261
|
+
raise Error::ParseError, "No arguments left... expected #{klass_}"
|
|
262
|
+
end
|
|
263
|
+
if klass_ && !val_.is_a?(klass_)
|
|
264
|
+
raise Error::ParseError, "Expected #{klass_} but got #{val_.class}"
|
|
265
|
+
end
|
|
266
|
+
val_
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
#
|
|
3
|
+
# Proj4 wrapper for RGeo
|
|
4
|
+
#
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
module RGeo
|
|
8
|
+
module CoordSys
|
|
9
|
+
# This is a Ruby wrapper around a Proj4 coordinate system.
|
|
10
|
+
# It represents a single geographic coordinate system, which may be
|
|
11
|
+
# a flat projection, a geocentric (3-dimensional) coordinate system,
|
|
12
|
+
# or a geographic (latitude-longitude) coordinate system.
|
|
13
|
+
#
|
|
14
|
+
# Generally, these are used to define the projection for a
|
|
15
|
+
# Feature::Factory. You can then convert between coordinate systems
|
|
16
|
+
# by casting geometries between such factories using the :project
|
|
17
|
+
# option. You may also use this object directly to perform low-level
|
|
18
|
+
# coordinate transformations.
|
|
19
|
+
|
|
20
|
+
class Proj4
|
|
21
|
+
def inspect # :nodoc:
|
|
22
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} #{canonical_str.inspect}>"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s # :nodoc:
|
|
26
|
+
canonical_str
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def hash # :nodoc:
|
|
30
|
+
@hash ||= canonical_hash.hash
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns true if this Proj4 is equivalent to the given Proj4.
|
|
34
|
+
#
|
|
35
|
+
# Note: this tests for equivalence by comparing only the hash
|
|
36
|
+
# definitions of the Proj4 objects, and returning true if those
|
|
37
|
+
# definitions are equivalent. In some cases, this may still return
|
|
38
|
+
# false even if the actual coordinate systems are identical, since
|
|
39
|
+
# there are sometimes multiple ways to express a given coordinate
|
|
40
|
+
# system.
|
|
41
|
+
|
|
42
|
+
def eql?(rhs_)
|
|
43
|
+
rhs_.class == self.class && rhs_.canonical_hash == canonical_hash && rhs_._radians? == _radians?
|
|
44
|
+
end
|
|
45
|
+
alias_method :==, :eql?
|
|
46
|
+
|
|
47
|
+
# Marshal support
|
|
48
|
+
|
|
49
|
+
def marshal_dump # :nodoc:
|
|
50
|
+
{ "rad" => radians?, "str" => original_str || canonical_str }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def marshal_load(data_) # :nodoc:
|
|
54
|
+
_set_value(data_["str"], data_["rad"])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Psych support
|
|
58
|
+
|
|
59
|
+
def encode_with(coder_) # :nodoc:
|
|
60
|
+
coder_["proj4"] = original_str || canonical_str
|
|
61
|
+
coder_["radians"] = radians?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def init_with(coder_) # :nodoc:
|
|
65
|
+
if coder_.type == :scalar
|
|
66
|
+
_set_value(coder_.scalar, false)
|
|
67
|
+
else
|
|
68
|
+
_set_value(coder_["proj4"], coder_["radians"])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns the "canonical" string definition for this coordinate
|
|
73
|
+
# system, as reported by Proj4. This may be slightly different
|
|
74
|
+
# from the definition used to construct this object.
|
|
75
|
+
|
|
76
|
+
def canonical_str
|
|
77
|
+
unless defined?(@canonical_str)
|
|
78
|
+
@canonical_str = _canonical_str
|
|
79
|
+
if @canonical_str.respond_to?(:force_encoding)
|
|
80
|
+
@canonical_str.force_encoding("US-ASCII")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
@canonical_str
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Returns the "canonical" hash definition for this coordinate
|
|
87
|
+
# system, as reported by Proj4. This may be slightly different
|
|
88
|
+
# from the definition used to construct this object.
|
|
89
|
+
|
|
90
|
+
def canonical_hash
|
|
91
|
+
unless defined?(@canonical_hash)
|
|
92
|
+
@canonical_hash = {}
|
|
93
|
+
canonical_str.strip.split(/\s+/).each do |elem_|
|
|
94
|
+
@canonical_hash[Regexp.last_match(1)] = Regexp.last_match(3) if elem_ =~ /^\+(\w+)(=(\S+))?$/
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
@canonical_hash
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns the string definition originally used to construct this
|
|
101
|
+
# object. Returns nil if this object wasn't created by a string
|
|
102
|
+
# definition; i.e. if it was created using get_geographic.
|
|
103
|
+
|
|
104
|
+
def original_str
|
|
105
|
+
_original_str
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Returns true if this Proj4 object is a geographic (lat-long)
|
|
109
|
+
# coordinate system.
|
|
110
|
+
|
|
111
|
+
def geographic?
|
|
112
|
+
_geographic?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Returns true if this Proj4 object is a geocentric (3dz)
|
|
116
|
+
# coordinate system.
|
|
117
|
+
|
|
118
|
+
def geocentric?
|
|
119
|
+
_geocentric?
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Returns true if this Proj4 object uses radians rather than degrees
|
|
123
|
+
# if it is a geographic coordinate system.
|
|
124
|
+
|
|
125
|
+
def radians?
|
|
126
|
+
_radians?
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Get the geographic (unprojected lat-long) coordinate system
|
|
130
|
+
# corresponding to this coordinate system; i.e. the one that uses
|
|
131
|
+
# the same ellipsoid and datum.
|
|
132
|
+
|
|
133
|
+
def get_geographic
|
|
134
|
+
_get_geographic
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class << self
|
|
138
|
+
# Returns true if Proj4 is supported in this installation.
|
|
139
|
+
# If this returns false, the other methods such as create
|
|
140
|
+
# will not work.
|
|
141
|
+
|
|
142
|
+
def supported?
|
|
143
|
+
respond_to?(:_create)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Returns the Proj library version as a string of the format "x.y.z".
|
|
147
|
+
|
|
148
|
+
def version
|
|
149
|
+
::RGeo::VERSION
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Create a new Proj4 object, given a definition, which may be
|
|
153
|
+
# either a string or a hash. Returns nil if the given definition
|
|
154
|
+
# is invalid or Proj4 is not supported.
|
|
155
|
+
#
|
|
156
|
+
# Recognized options include:
|
|
157
|
+
#
|
|
158
|
+
# [<tt>:radians</tt>]
|
|
159
|
+
# If set to true, then this proj4 will represent geographic
|
|
160
|
+
# (latitude/longitude) coordinates in radians rather than
|
|
161
|
+
# degrees. If this is a geographic coordinate system, then its
|
|
162
|
+
# units will be in radians. If this is a projected coordinate
|
|
163
|
+
# system, then its units will be unchanged, but any geographic
|
|
164
|
+
# coordinate system obtained using get_geographic will use
|
|
165
|
+
# radians as its units. If this is a geocentric or other type of
|
|
166
|
+
# coordinate system, this has no effect. Default is false.
|
|
167
|
+
# (That is all coordinates are in degrees by default.)
|
|
168
|
+
|
|
169
|
+
def create(defn_, opts_ = {})
|
|
170
|
+
result_ = nil
|
|
171
|
+
if supported?
|
|
172
|
+
if defn_.is_a?(::Hash)
|
|
173
|
+
defn_ = defn_.map { |k_, v_| v_ ? "+#{k_}=#{v_}" : "+#{k_}" }.join(" ")
|
|
174
|
+
end
|
|
175
|
+
unless defn_ =~ /^\s*\+/
|
|
176
|
+
defn_ = defn_.sub(/^(\s*)/, '\1+').gsub(/(\s+)([^+\s])/, '\1+\2')
|
|
177
|
+
end
|
|
178
|
+
result_ = _create(defn_, opts_[:radians])
|
|
179
|
+
result_ = nil unless result_._valid?
|
|
180
|
+
end
|
|
181
|
+
result_
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Create a new Proj4 object, given a definition, which may be
|
|
185
|
+
# either a string or a hash. Raises Error::UnsupportedOperation
|
|
186
|
+
# if the given definition is invalid or Proj4 is not supported.
|
|
187
|
+
#
|
|
188
|
+
# Recognized options include:
|
|
189
|
+
#
|
|
190
|
+
# [<tt>:radians</tt>]
|
|
191
|
+
# If set to true, then this proj4 will represent geographic
|
|
192
|
+
# (latitude/longitude) coordinates in radians rather than
|
|
193
|
+
# degrees. If this is a geographic coordinate system, then its
|
|
194
|
+
# units will be in radians. If this is a projected coordinate
|
|
195
|
+
# system, then its units will be unchanged, but any geographic
|
|
196
|
+
# coordinate system obtained using get_geographic will use
|
|
197
|
+
# radians as its units. If this is a geocentric or other type of
|
|
198
|
+
# coordinate system, this has no effect. Default is false.
|
|
199
|
+
# (That is all coordinates are in degrees by default.)
|
|
200
|
+
|
|
201
|
+
def new(defn_, opts_ = {})
|
|
202
|
+
result_ = create(defn_, opts_)
|
|
203
|
+
unless result_
|
|
204
|
+
raise Error::UnsupportedOperation, "Proj4 not supported in this installation"
|
|
205
|
+
end
|
|
206
|
+
result_
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Low-level coordinate transform method.
|
|
210
|
+
# Transforms the given coordinate (x, y, [z]) from one proj4
|
|
211
|
+
# coordinate system to another. Returns an array with either two
|
|
212
|
+
# or three elements.
|
|
213
|
+
|
|
214
|
+
def transform_coords(from_proj_, to_proj_, x_, y_, z_ = nil)
|
|
215
|
+
if !from_proj_._radians? && from_proj_._geographic?
|
|
216
|
+
x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
|
|
217
|
+
y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
|
|
218
|
+
end
|
|
219
|
+
result_ = _transform_coords(from_proj_, to_proj_, x_, y_, z_)
|
|
220
|
+
if result_ && !to_proj_._radians? && to_proj_._geographic?
|
|
221
|
+
result_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
|
|
222
|
+
result_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
|
|
223
|
+
end
|
|
224
|
+
result_
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Low-level geometry transform method.
|
|
228
|
+
# Transforms the given geometry between the given two projections.
|
|
229
|
+
# The resulting geometry is constructed using the to_factory.
|
|
230
|
+
# Any projections associated with the factories themselves are
|
|
231
|
+
# ignored.
|
|
232
|
+
|
|
233
|
+
def transform(from_proj_, from_geometry_, to_proj_, to_factory_)
|
|
234
|
+
case from_geometry_
|
|
235
|
+
when Feature::Point
|
|
236
|
+
_transform_point(from_proj_, from_geometry_, to_proj_, to_factory_)
|
|
237
|
+
when Feature::Line
|
|
238
|
+
to_factory_.line(from_geometry_.points.map { |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
|
|
239
|
+
when Feature::LinearRing
|
|
240
|
+
_transform_linear_ring(from_proj_, from_geometry_, to_proj_, to_factory_)
|
|
241
|
+
when Feature::LineString
|
|
242
|
+
to_factory_.line_string(from_geometry_.points.map { |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
|
|
243
|
+
when Feature::Polygon
|
|
244
|
+
_transform_polygon(from_proj_, from_geometry_, to_proj_, to_factory_)
|
|
245
|
+
when Feature::MultiPoint
|
|
246
|
+
to_factory_.multi_point(from_geometry_.map { |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
|
|
247
|
+
when Feature::MultiLineString
|
|
248
|
+
to_factory_.multi_line_string(from_geometry_.map { |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
|
|
249
|
+
when Feature::MultiPolygon
|
|
250
|
+
to_factory_.multi_polygon(from_geometry_.map { |p_| _transform_polygon(from_proj_, p_, to_proj_, to_factory_) })
|
|
251
|
+
when Feature::GeometryCollection
|
|
252
|
+
to_factory_.collection(from_geometry_.map { |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def _transform_point(from_proj_, from_point_, to_proj_, to_factory_) # :nodoc:
|
|
257
|
+
from_factory_ = from_point_.factory
|
|
258
|
+
from_has_z_ = from_factory_.property(:has_z_coordinate)
|
|
259
|
+
from_has_m_ = from_factory_.property(:has_m_coordinate)
|
|
260
|
+
to_has_z_ = to_factory_.property(:has_z_coordinate)
|
|
261
|
+
to_has_m_ = to_factory_.property(:has_m_coordinate)
|
|
262
|
+
x_ = from_point_.x
|
|
263
|
+
y_ = from_point_.y
|
|
264
|
+
if !from_proj_._radians? && from_proj_._geographic?
|
|
265
|
+
x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
|
|
266
|
+
y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
|
|
267
|
+
end
|
|
268
|
+
coords_ = _transform_coords(from_proj_, to_proj_, x_, y_, from_has_z_ ? from_point_.z : nil)
|
|
269
|
+
if coords_
|
|
270
|
+
if !to_proj_._radians? && to_proj_._geographic?
|
|
271
|
+
coords_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
|
|
272
|
+
coords_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
|
|
273
|
+
end
|
|
274
|
+
extras_ = []
|
|
275
|
+
extras_ << coords_[2].to_f if to_has_z_
|
|
276
|
+
extras_ << from_has_m_ ? from_point_.m : 0.0 if to_has_m_
|
|
277
|
+
to_factory_.point(coords_[0], coords_[1], *extras_)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def _transform_linear_ring(from_proj_, from_ring_, to_proj_, to_factory_) # :nodoc:
|
|
282
|
+
to_factory_.linear_ring(from_ring_.points[0..-2].map { |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def _transform_polygon(from_proj_, from_polygon_, to_proj_, to_factory_) # :nodoc:
|
|
286
|
+
ext_ = _transform_linear_ring(from_proj_, from_polygon_.exterior_ring, to_proj_, to_factory_)
|
|
287
|
+
int_ = from_polygon_.interior_rings.map { |r_| _transform_linear_ring(from_proj_, r_, to_proj_, to_factory_) }
|
|
288
|
+
to_factory_.polygon(ext_, int_)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|