1
+ <?php
2
+
3
+
4
+ namespace Academe \Proj ;
5
+
6
+ /**
7
+ * This class parses and holds a Proj4 configuration.
8
+ * @package Academe\Proj
9
+ */
10
+ class Proj4Config
11
+ {
12
+ /**
13
+ * @var string The source string that this object was constructed from.
14
+ */
15
+ private $ source ;
16
+
17
+ /**
18
+ * @var Semimajor radius of the ellipsoid axis
19
+ */
20
+ protected $ a ;
21
+
22
+ /**
23
+ * @var ? Used with Oblique Mercator and possibly a few others
24
+ */
25
+ protected $ alpha ;
26
+
27
+ /**
28
+ * @var Axis orientation (new in 4.8.0)
29
+ */
30
+ protected $ axis ;
31
+
32
+ /**
33
+ * @var Semiminor radius of the ellipsoid axis
34
+ */
35
+ protected $ b ;
36
+
37
+ /**
38
+ * @var stringDatum name (see `proj -ld`)
39
+ */
40
+ protected $ datum ;
41
+
42
+ /**
43
+ * @var string Ellipsoid name (see `proj -le`)
44
+ */
45
+ protected $ ellps = 'WGS84 ' ;
46
+
47
+ /**
48
+ * @var float Scaling factor (old name)
49
+ */
50
+ protected $ k ;
51
+
52
+ /**
53
+ * @var float Scaling factor (new name)
54
+ */
55
+ protected $ k_0 ;
56
+
57
+ /**
58
+ * @var float Latitude of origin
59
+ */
60
+ protected $ lat_0 ;
61
+
62
+ /**
63
+ * @var float Latitude of first standard parallel
64
+ */
65
+ protected $ lat_1 ;
66
+
67
+ /**
68
+ * @var float Latitude of second standard parallel
69
+ */
70
+ protected $ lat_2 ;
71
+
72
+ /**
73
+ * @var float Latitude of true scale
74
+ */
75
+ protected $ lat_ts ;
76
+
77
+ /**
78
+ * @var float Central meridian
79
+ */
80
+ protected $ lon_0 ;
81
+
82
+ /**
83
+ * @var ? Longitude used with Oblique Mercator and possibly a few others
84
+ */
85
+ protected $ lonc ;
86
+
87
+ /**
88
+ * @var Center longitude to use for wrapping (see below)
89
+ */
90
+ protected $ lon_wrap ;
91
+
92
+ /**
93
+ * @var Filename of NTv2 grid file to use for datum transforms (see below)
94
+ */
95
+ protected $ nadgrids ;
96
+
97
+ /**
98
+ * @var Don't use the /usr/share/proj/proj_def.dat defaults file
99
+ */
100
+ protected $ no_defs ;
101
+
102
+ /**
103
+ * @var Allow longitude output outside -180 to 180 range, disables wrapping (see below)
104
+ */
105
+ protected $ over ;
106
+
107
+ /**
108
+ * @var string Alternate prime meridian (typically a city name, see below)
109
+ */
110
+ protected $ pm ;
111
+
112
+ /**
113
+ * @var string Projection name (see `proj -l`)
114
+ */
115
+ protected $ proj ;
116
+ /**
117
+ * @var Denotes southern hemisphere UTM zone
118
+ */
119
+ protected $ south ;
120
+
121
+ /**
122
+ * @var float Multiplier to convert map units to 1.0m
123
+ */
124
+ protected $ to_meter ;
125
+
126
+ /**
127
+ * @var 3 or 7 term datum transform parameters (see below)
128
+ */
129
+ protected $ towgs84 ;
130
+
131
+ /**
132
+ * @var meters, US survey feet, etc.
133
+ */
134
+ protected $ units ;
135
+
136
+ /**
137
+ * @var vertical conversion to meters.
138
+ */
139
+ protected $ vto_meter ;
140
+
141
+ /**
142
+ * @var vertical units.
143
+ */
144
+ protected $ vunits ;
145
+
146
+ /**
147
+ * @var int False easting
148
+ */
149
+ protected $ x_0 ;
150
+
151
+ /**
152
+ * @var int False northing
153
+ */
154
+ protected $ y_0 ;
155
+
156
+ /**
157
+ * @var UTM zone
158
+ */
159
+ protected $ zone ;
160
+
161
+ /**
162
+ * @var string Title of this definition.
163
+ */
164
+ protected $ title ;
165
+
166
+ /**
167
+ * @var float
168
+ */
169
+ protected $ from_greenwich = 0.0 ;
170
+
171
+ public function __construct ($ configurationString )
172
+ {
173
+ $ this ->source = $ configurationString ;
174
+ $ params = $ this ->parseIntoArray ($ configurationString );
175
+ foreach ($ params as $ key => $ value ) {
176
+ $ attribute = lcfirst ($ key );
177
+ $ setter = 'set ' . ucfirst ($ attribute );
178
+ if (method_exists ($ this , $ setter )) {
179
+ $ this ->$ setter ($ value );
180
+ } elseif (property_exists ($ this , $ attribute )) {
181
+ $ this ->$ attribute = $ value ;
182
+ } else {
183
+ throw new \Exception ("Unknown parameter: ' $ key' for definition: $ configurationString " );
184
+ }
185
+ }
186
+
187
+ }
188
+
189
+ /**
190
+ * Static because it does not need $this, public because someone might want to use it outside the context
191
+ * of creating an instance of this class.
192
+ * @param $string
193
+ */
194
+ public static function parseIntoArray ($ string )
195
+ {
196
+ preg_match_all ('/\+(?<key>\w+)=(?<val>.*?)(?:\+|$)/ ' , $ string , $ matches );
197
+ $ result = [];
198
+ foreach ($ matches ['key ' ] as $ i => $ key ) {
199
+ $ result [$ key ] = self ::convert ($ matches ['val ' ][$ i ], $ key );
200
+
201
+ }
202
+ return $ result ;
203
+ }
204
+
205
+ /**
206
+ * This converts PROJ4 values to native PHP values.
207
+ * The goal is to be flexible and speed is not a primary concern (at this point).
208
+ * @param string $value
209
+ * @param $key Optional key to help with deciding the format.
210
+ * @return float|null|int|string
211
+ */
212
+ public static function convert ($ value , $ key = null )
213
+ {
214
+ $ value = trim ($ value );
215
+ if (strpos ($ value , '/ ' ) !== false
216
+ && count ($ parts = explode ('/ ' , $ value )) === 2
217
+ && is_numeric ($ parts [0 ])
218
+ && is_numeric ($ parts [1 ])
219
+ ) {
220
+ return floatval ($ parts [0 ]) / floatval ($ parts [1 ]);
221
+ } elseif (ctype_digit ($ value )) {
222
+ return intval ($ value );
223
+ } elseif (is_numeric ($ value )) {
224
+ return floatval ($ value );
225
+ } elseif (empty ($ value )) {
226
+ return null ;
227
+ } elseif (preg_match ('/^(-?[0-9]+(\.[0-9]*)?)(,(-?[0-9]+(\.[0-9]*)?))*$/ ' , $ value , $ matches )) {
228
+ return array_map ('self::convert ' , explode (', ' , $ value ));
229
+ } elseif (preg_match ('/^(?<k>[a-zA-Z\d]*?)=(?<v>.*?)$/ ' , $ value , $ matches )) {
230
+ return [
231
+ $ matches ['k ' ] => self ::convert ($ matches ['v ' ], $ matches ['k ' ])
232
+ ];
233
+ } else {
234
+ // echo "Can't convert: $value\n";
235
+
236
+ }
237
+ return $ value ;
238
+ }
239
+
240
+ /**
241
+ * @return Ellipsoid
242
+ */
243
+ public function getEllipsoid ()
244
+ {
245
+ // This is just to show it is working, obviously it needs refactoring to load this in a more centralized matter.
246
+ $ definitions = json_decode (file_get_contents (__DIR__ . '/data/ellipsoids.json ' ), true );
247
+ if (isset ($ definitions [$ this ->ellps ])) {
248
+ return new Ellipsoid ($ definitions [$ this ->ellps ]);
249
+ } else {
250
+ throw new \Exception ("Can't find definition for ellipsoid: $ this ->ellps " );
251
+ }
252
+
253
+ }
254
+
255
+ /**
256
+ * @return Datum
257
+ */
258
+ public function getDatum ()
259
+ {
260
+ if (!isset ($ this ->towgs84 )) {
261
+ // These 3 are translation parameters, 0 is an identity for translation.
262
+ return new Datum ([0 , 0 , 0 ], $ this ->getEllipsoid ());
263
+ } else {
264
+ return new Datum ($ this ->towgs84 , $ this ->getEllipsoid ());
265
+ }
266
+ }
267
+
268
+ }
0 commit comments