1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* phpMyAdmin ShapeFile library |
4
|
|
|
* <https://github.com/phpmyadmin/shapefile/> |
5
|
|
|
* |
6
|
|
|
* Copyright 2006-2007 Ovidio <ovidio AT users.sourceforge.net> |
7
|
|
|
* Copyright 2016 Michal Čihař <[email protected]> |
8
|
|
|
* |
9
|
|
|
* This program is free software; you can redistribute it and/or |
10
|
|
|
* modify it under the terms of the GNU General Public License |
11
|
|
|
* as published by the Free Software Foundation. |
12
|
|
|
* |
13
|
|
|
* This program is distributed in the hope that it will be useful, |
14
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
* GNU General Public License for more details. |
17
|
|
|
* |
18
|
|
|
* You should have received a copy of the GNU General Public License |
19
|
|
|
* along with this program; if not, you can download one from |
20
|
|
|
* https://www.gnu.org/copyleft/gpl.html. |
21
|
|
|
*/ |
22
|
|
|
namespace ShapeFile; |
23
|
|
|
|
24
|
|
|
class ShapeRecord { |
25
|
|
|
private $SHPFile = null; |
26
|
|
|
private $DBFFile = null; |
27
|
|
|
private $ShapeFile = null; |
28
|
|
|
|
29
|
|
|
private $size = 0; |
30
|
|
|
private $read = 0; |
31
|
|
|
|
32
|
|
|
public $recordNumber = null; |
33
|
|
|
public $shapeType = null; |
34
|
|
|
|
35
|
|
|
public $lastError = ''; |
36
|
|
|
|
37
|
|
|
public $SHPData = array(); |
38
|
|
|
public $DBFData = array(); |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @param integer $shapeType |
42
|
|
|
*/ |
43
|
20 |
|
public function __construct($shapeType) { |
44
|
20 |
|
$this->shapeType = $shapeType; |
45
|
20 |
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @param ShapeFile $ShapeFile |
49
|
|
|
*/ |
50
|
19 |
|
public function loadFromFile(&$ShapeFile, &$SHPFile, &$DBFFile) { |
51
|
19 |
|
$this->ShapeFile = $ShapeFile; |
52
|
19 |
|
$this->SHPFile = $SHPFile; |
53
|
19 |
|
$this->DBFFile = $DBFFile; |
54
|
19 |
|
$this->_loadHeaders(); |
55
|
|
|
|
56
|
|
|
/* No header read */ |
57
|
19 |
|
if ($this->read == 0) { |
58
|
19 |
|
return; |
59
|
|
|
} |
60
|
|
|
|
61
|
19 |
|
switch ($this->shapeType) { |
62
|
19 |
|
case 0: |
63
|
|
|
$this->_loadNullRecord(); |
64
|
|
|
break; |
65
|
19 |
|
case 1: |
66
|
4 |
|
$this->_loadPointRecord(); |
67
|
4 |
|
break; |
68
|
15 |
|
case 21: |
69
|
1 |
|
$this->_loadPointMRecord(); |
70
|
1 |
|
break; |
71
|
14 |
|
case 11: |
72
|
1 |
|
$this->_loadPointZRecord(); |
73
|
1 |
|
break; |
74
|
13 |
|
case 3: |
75
|
1 |
|
$this->_loadPolyLineRecord(); |
76
|
1 |
|
break; |
77
|
12 |
|
case 23: |
78
|
1 |
|
$this->_loadPolyLineMRecord(); |
79
|
1 |
|
break; |
80
|
11 |
|
case 13: |
81
|
1 |
|
$this->_loadPolyLineZRecord(); |
82
|
1 |
|
break; |
83
|
10 |
|
case 5: |
84
|
3 |
|
$this->_loadPolygonRecord(); |
85
|
3 |
|
break; |
86
|
7 |
|
case 25: |
87
|
1 |
|
$this->_loadPolygonMRecord(); |
88
|
1 |
|
break; |
89
|
6 |
|
case 15: |
90
|
2 |
|
$this->_loadPolygonZRecord(); |
91
|
2 |
|
break; |
92
|
4 |
|
case 8: |
93
|
1 |
|
$this->_loadMultiPointRecord(); |
94
|
1 |
|
break; |
95
|
3 |
|
case 28: |
96
|
1 |
|
$this->_loadMultiPointMRecord(); |
97
|
1 |
|
break; |
98
|
2 |
|
case 18: |
99
|
2 |
|
$this->_loadMultiPointZRecord(); |
100
|
2 |
|
break; |
101
|
|
|
default: |
102
|
|
|
$this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)); |
103
|
|
|
break; |
104
|
19 |
|
} |
105
|
|
|
|
106
|
|
|
/* We need to skip rest of the record */ |
107
|
19 |
|
while ($this->read < $this->size) { |
108
|
6 |
|
$this->_loadData('V', 4); |
109
|
6 |
|
} |
110
|
|
|
|
111
|
|
|
/* Check if we didn't read too much */ |
112
|
19 |
|
if ($this->read != $this->size) { |
113
|
|
|
$this->setError(sprintf('Failed to parse record, read=%d, size=%d', $this->read, $this->size)); |
114
|
|
|
} |
115
|
|
|
|
116
|
19 |
|
if (ShapeFile::supports_dbase() && isset($this->DBFFile)) { |
117
|
|
|
$this->_loadDBFData(); |
118
|
|
|
} |
119
|
19 |
|
} |
120
|
|
|
|
121
|
12 |
|
public function saveToFile(&$SHPFile, &$DBFFile, $recordNumber) { |
122
|
12 |
|
$this->SHPFile = $SHPFile; |
123
|
12 |
|
$this->DBFFile = $DBFFile; |
124
|
12 |
|
$this->recordNumber = $recordNumber; |
125
|
12 |
|
$this->_saveHeaders(); |
126
|
|
|
|
127
|
12 |
|
switch ($this->shapeType) { |
128
|
12 |
|
case 0: |
129
|
|
|
// Nothing to save |
130
|
|
|
break; |
131
|
12 |
|
case 1: |
132
|
1 |
|
$this->_savePointRecord(); |
133
|
1 |
|
break; |
134
|
11 |
|
case 21: |
135
|
1 |
|
$this->_savePointMRecord(); |
136
|
1 |
|
break; |
137
|
10 |
|
case 11: |
138
|
1 |
|
$this->_savePointZRecord(); |
139
|
1 |
|
break; |
140
|
9 |
|
case 3: |
141
|
1 |
|
$this->_savePolyLineRecord(); |
142
|
1 |
|
break; |
143
|
8 |
|
case 23: |
144
|
1 |
|
$this->_savePolyLineMRecord(); |
145
|
1 |
|
break; |
146
|
7 |
|
case 13: |
147
|
1 |
|
$this->_savePolyLineZRecord(); |
148
|
1 |
|
break; |
149
|
6 |
|
case 5: |
150
|
1 |
|
$this->_savePolygonRecord(); |
151
|
1 |
|
break; |
152
|
5 |
|
case 25: |
153
|
1 |
|
$this->_savePolygonMRecord(); |
154
|
1 |
|
break; |
155
|
4 |
|
case 15: |
156
|
1 |
|
$this->_savePolygonZRecord(); |
157
|
1 |
|
break; |
158
|
3 |
|
case 8: |
159
|
1 |
|
$this->_saveMultiPointRecord(); |
160
|
1 |
|
break; |
161
|
2 |
|
case 28: |
162
|
1 |
|
$this->_saveMultiPointMRecord(); |
163
|
1 |
|
break; |
164
|
1 |
|
case 18: |
165
|
1 |
|
$this->_saveMultiPointZRecord(); |
166
|
1 |
|
break; |
167
|
|
|
default: |
168
|
|
|
$this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)); |
169
|
|
|
break; |
170
|
12 |
|
} |
171
|
12 |
|
if (ShapeFile::supports_dbase() && isset($this->DBFFile)) { |
172
|
|
|
$this->_saveDBFData(); |
173
|
|
|
} |
174
|
12 |
|
} |
175
|
|
|
|
176
|
12 |
|
public function updateDBFInfo($header) { |
177
|
12 |
|
$tmp = $this->DBFData; |
178
|
12 |
|
unset($this->DBFData); |
179
|
12 |
|
$this->DBFData = array(); |
180
|
12 |
|
foreach ($header as $value) { |
181
|
12 |
|
$this->DBFData[$value[0]] = (isset($tmp[$value[0]])) ? $tmp[$value[0]] : ''; |
182
|
12 |
|
} |
183
|
12 |
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Reads data |
187
|
|
|
* |
188
|
|
|
* @param string $type type for unpack() |
189
|
|
|
* @param int $count number of bytes |
190
|
|
|
* |
191
|
|
|
* @return mixed |
192
|
|
|
*/ |
193
|
19 |
|
private function _loadData($type, $count) |
194
|
|
|
{ |
195
|
19 |
|
$data = $this->ShapeFile->readSHP($count); |
196
|
19 |
|
if ($data === false) { |
197
|
|
|
return false; |
198
|
|
|
} |
199
|
19 |
|
$this->read += strlen($data); |
200
|
19 |
|
return Util::loadData($type, $data); |
201
|
|
|
} |
202
|
|
|
|
203
|
19 |
|
private function _loadHeaders() { |
204
|
19 |
|
$this->shapeType = false; |
205
|
19 |
|
$this->recordNumber = $this->_loadData('N', 4); |
206
|
19 |
|
if ($this->recordNumber === false) { |
207
|
19 |
|
return; |
208
|
|
|
} |
209
|
|
|
// We read the length of the record |
210
|
19 |
|
$this->size = $this->_loadData('N', 4); |
211
|
19 |
|
if ($this->size === false) { |
212
|
|
|
return; |
213
|
|
|
} |
214
|
19 |
|
$this->size = $this->size * 2 + 8; |
215
|
19 |
|
$this->shapeType = $this->_loadData('V', 4); |
216
|
19 |
|
} |
217
|
|
|
|
218
|
12 |
|
private function _saveHeaders() { |
219
|
12 |
|
fwrite($this->SHPFile, pack('N', $this->recordNumber)); |
220
|
12 |
|
fwrite($this->SHPFile, pack('N', $this->getContentLength())); |
221
|
12 |
|
fwrite($this->SHPFile, pack('V', $this->shapeType)); |
222
|
12 |
|
} |
223
|
|
|
|
224
|
19 |
|
private function _loadPoint() { |
225
|
19 |
|
$data = array(); |
226
|
|
|
|
227
|
19 |
|
$data['x'] = $this->_loadData('d', 8); |
228
|
19 |
|
$data['y'] = $this->_loadData('d', 8); |
229
|
|
|
|
230
|
19 |
|
return $data; |
231
|
|
|
} |
232
|
|
|
|
233
|
1 |
|
private function _loadPointM() { |
234
|
1 |
|
$data = $this->_loadPoint(); |
235
|
|
|
|
236
|
1 |
|
$data['m'] = $this->_loadData('d', 8); |
237
|
|
|
|
238
|
1 |
|
return $data; |
239
|
|
|
} |
240
|
|
|
|
241
|
1 |
|
private function _loadPointZ() { |
242
|
1 |
|
$data = $this->_loadPoint(); |
243
|
|
|
|
244
|
1 |
|
$data['z'] = $this->_loadData('d', 8); |
245
|
1 |
|
$data['m'] = $this->_loadData('d', 8); |
246
|
|
|
|
247
|
1 |
|
return $data; |
248
|
|
|
} |
249
|
|
|
|
250
|
10 |
|
private function _savePoint($data) { |
251
|
10 |
|
fwrite($this->SHPFile, Util::packDouble($data['x'])); |
252
|
10 |
|
fwrite($this->SHPFile, Util::packDouble($data['y'])); |
253
|
10 |
|
} |
254
|
|
|
|
255
|
1 |
|
private function _savePointM($data) { |
256
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['x'])); |
257
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['y'])); |
258
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['m'])); |
259
|
1 |
|
} |
260
|
|
|
|
261
|
1 |
|
private function _savePointZ($data) { |
262
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['x'])); |
263
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['y'])); |
264
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['z'])); |
265
|
1 |
|
fwrite($this->SHPFile, Util::packDouble($data['m'])); |
266
|
1 |
|
} |
267
|
|
|
|
268
|
|
|
private function _loadNullRecord() { |
269
|
|
|
$this->SHPData = array(); |
270
|
|
|
} |
271
|
|
|
|
272
|
4 |
|
private function _loadPointRecord() { |
273
|
4 |
|
$this->SHPData = $this->_loadPoint(); |
274
|
4 |
|
} |
275
|
|
|
|
276
|
1 |
|
private function _loadPointMRecord() { |
277
|
1 |
|
$this->SHPData = $this->_loadPointM(); |
278
|
1 |
|
} |
279
|
|
|
|
280
|
1 |
|
private function _loadPointZRecord() { |
281
|
1 |
|
$this->SHPData = $this->_loadPointZ(); |
282
|
1 |
|
} |
283
|
|
|
|
284
|
1 |
|
private function _savePointRecord() { |
285
|
1 |
|
$this->_savePoint($this->SHPData); |
286
|
1 |
|
} |
287
|
|
|
|
288
|
1 |
|
private function _savePointMRecord() { |
289
|
1 |
|
$this->_savePointM($this->SHPData); |
290
|
1 |
|
} |
291
|
|
|
|
292
|
1 |
|
private function _savePointZRecord() { |
293
|
1 |
|
$this->_savePointZ($this->SHPData); |
294
|
1 |
|
} |
295
|
|
|
|
296
|
13 |
|
private function _loadBBox() |
297
|
|
|
{ |
298
|
13 |
|
$this->SHPData['xmin'] = $this->_loadData('d', 8); |
299
|
13 |
|
$this->SHPData['ymin'] = $this->_loadData('d', 8); |
300
|
13 |
|
$this->SHPData['xmax'] = $this->_loadData('d', 8); |
301
|
13 |
|
$this->SHPData['ymax'] = $this->_loadData('d', 8); |
302
|
13 |
|
} |
303
|
|
|
|
304
|
4 |
|
private function _loadMultiPointRecord() { |
305
|
4 |
|
$this->SHPData = array(); |
306
|
4 |
|
$this->_loadBBox(); |
307
|
|
|
|
308
|
4 |
|
$this->SHPData['numpoints'] = $this->_loadData('V', 4); |
309
|
|
|
|
310
|
4 |
|
for ($i = 0; $i < $this->SHPData['numpoints']; $i++) { |
311
|
4 |
|
$this->SHPData['points'][] = $this->_loadPoint(); |
312
|
4 |
|
} |
313
|
4 |
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* @param string $type |
317
|
|
|
*/ |
318
|
3 |
|
private function _loadMultiPointMZRecord($type) |
319
|
|
|
{ |
320
|
|
|
/* The m dimension is optional, depends on bounding box data */ |
321
|
3 |
|
if ($type == 'm' && !$this->ShapeFile->hasMeasure()) { |
322
|
3 |
|
return; |
323
|
|
|
} |
324
|
|
|
|
325
|
2 |
|
$this->SHPData[$type.'min'] = $this->_loadData('d', 8); |
326
|
2 |
|
$this->SHPData[$type.'max'] = $this->_loadData('d', 8); |
327
|
|
|
|
328
|
2 |
|
for ($i = 0; $i < $this->SHPData['numpoints']; $i++) { |
329
|
2 |
|
$this->SHPData['points'][$i][$type] = $this->_loadData('d', 8); |
330
|
2 |
|
} |
331
|
2 |
|
} |
332
|
|
|
|
333
|
1 |
|
private function _loadMultiPointMRecord() { |
334
|
1 |
|
$this->_loadMultiPointRecord(); |
335
|
|
|
|
336
|
1 |
|
$this->_loadMultiPointMZRecord('m'); |
337
|
1 |
|
} |
338
|
|
|
|
339
|
2 |
|
private function _loadMultiPointZRecord() { |
340
|
2 |
|
$this->_loadMultiPointRecord(); |
341
|
|
|
|
342
|
2 |
|
$this->_loadMultiPointMZRecord('z'); |
343
|
2 |
|
$this->_loadMultiPointMZRecord('m'); |
344
|
2 |
|
} |
345
|
|
|
|
346
|
3 |
|
private function _saveMultiPointRecord() { |
347
|
3 |
|
fwrite($this->SHPFile, pack('dddd', $this->SHPData['xmin'], $this->SHPData['ymin'], $this->SHPData['xmax'], $this->SHPData['ymax'])); |
348
|
|
|
|
349
|
3 |
|
fwrite($this->SHPFile, pack('V', $this->SHPData['numpoints'])); |
350
|
|
|
|
351
|
3 |
|
for ($i = 0; $i < $this->SHPData['numpoints']; $i++) { |
352
|
3 |
|
$this->_savePoint($this->SHPData['points'][$i]); |
353
|
3 |
|
} |
354
|
3 |
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* @param string $type |
358
|
|
|
*/ |
359
|
2 |
|
private function _saveMultiPointMZRecord($type) { |
360
|
|
|
|
361
|
2 |
|
fwrite($this->SHPFile, pack('dd', $this->SHPData[$type.'min'], $this->SHPData[$type.'max'])); |
362
|
|
|
|
363
|
2 |
|
for ($i = 0; $i < $this->SHPData['numpoints']; $i++) { |
364
|
2 |
|
fwrite($this->SHPFile, Util::packDouble($this->SHPData['points'][$i][$type])); |
365
|
2 |
|
} |
366
|
2 |
|
} |
367
|
|
|
|
368
|
1 |
|
private function _saveMultiPointMRecord() { |
369
|
1 |
|
$this->_saveMultiPointRecord(); |
370
|
|
|
|
371
|
1 |
|
$this->_saveMultiPointMZRecord('m'); |
372
|
1 |
|
} |
373
|
|
|
|
374
|
1 |
|
private function _saveMultiPointZRecord() { |
375
|
1 |
|
$this->_saveMultiPointRecord(); |
376
|
|
|
|
377
|
1 |
|
$this->_saveMultiPointMZRecord('z'); |
378
|
1 |
|
$this->_saveMultiPointMZRecord('m'); |
379
|
1 |
|
} |
380
|
|
|
|
381
|
9 |
|
private function _loadPolyLineRecord() { |
382
|
9 |
|
$this->SHPData = array(); |
383
|
9 |
|
$this->_loadBBox(); |
384
|
|
|
|
385
|
9 |
|
$this->SHPData['numparts'] = $this->_loadData('V', 4); |
386
|
9 |
|
$this->SHPData['numpoints'] = $this->_loadData('V', 4); |
387
|
|
|
|
388
|
9 |
|
$numparts = $this->SHPData['numparts']; |
389
|
9 |
|
$numpoints = $this->SHPData['numpoints']; |
390
|
|
|
|
391
|
9 |
|
for ($i = 0; $i < $numparts; $i++) { |
392
|
9 |
|
$this->SHPData['parts'][$i] = $this->_loadData('V', 4); |
393
|
9 |
|
} |
394
|
|
|
|
395
|
9 |
|
$part = 0; |
396
|
9 |
|
for ($i = 0; $i < $numpoints; $i++) { |
397
|
9 |
View Code Duplication |
if ($part + 1 < $numparts && $this->SHPData['parts'][$part + 1] == $i) { |
398
|
8 |
|
$part++; |
399
|
8 |
|
} |
400
|
9 |
|
if (!isset($this->SHPData['parts'][$part]['points']) || !is_array($this->SHPData['parts'][$part]['points'])) { |
401
|
9 |
|
$this->SHPData['parts'][$part] = array('points' => array()); |
402
|
9 |
|
} |
403
|
9 |
|
$this->SHPData['parts'][$part]['points'][] = $this->_loadPoint(); |
404
|
9 |
|
} |
405
|
9 |
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* @param string $type |
409
|
|
|
*/ |
410
|
5 |
|
private function _loadPolyLineMZRecord($type) { |
411
|
|
|
/* The m dimension is optional, depends on bounding box data */ |
412
|
5 |
|
if ($type == 'm' && !$this->ShapeFile->hasMeasure()) { |
413
|
5 |
|
return; |
414
|
|
|
} |
415
|
|
|
|
416
|
3 |
|
$this->SHPData[$type.'min'] = $this->_loadData('d', 8); |
417
|
3 |
|
$this->SHPData[$type.'max'] = $this->_loadData('d', 8); |
418
|
|
|
|
419
|
3 |
|
$numparts = $this->SHPData['numparts']; |
420
|
3 |
|
$numpoints = $this->SHPData['numpoints']; |
421
|
|
|
|
422
|
3 |
|
$part = 0; |
423
|
3 |
|
for ($i = 0; $i < $numpoints; $i++) { |
424
|
3 |
View Code Duplication |
if ($part + 1 < $numparts && $this->SHPData['parts'][$part + 1] == $i) { |
425
|
|
|
$part++; |
426
|
|
|
} |
427
|
3 |
|
$this->SHPData['parts'][$part]['points'][$i][$type] = $this->_loadData('d', 8); |
428
|
3 |
|
} |
429
|
3 |
|
} |
430
|
|
|
|
431
|
2 |
|
private function _loadPolyLineMRecord() { |
432
|
2 |
|
$this->_loadPolyLineRecord(); |
433
|
|
|
|
434
|
2 |
|
$this->_loadPolyLineMZRecord('m'); |
435
|
2 |
|
} |
436
|
|
|
|
437
|
3 |
|
private function _loadPolyLineZRecord() { |
438
|
3 |
|
$this->_loadPolyLineRecord(); |
439
|
|
|
|
440
|
3 |
|
$this->_loadPolyLineMZRecord('z'); |
441
|
3 |
|
$this->_loadPolyLineMZRecord('m'); |
442
|
3 |
|
} |
443
|
|
|
|
444
|
6 |
|
private function _savePolyLineRecord() { |
445
|
6 |
|
fwrite($this->SHPFile, pack('dddd', $this->SHPData['xmin'], $this->SHPData['ymin'], $this->SHPData['xmax'], $this->SHPData['ymax'])); |
446
|
|
|
|
447
|
6 |
|
fwrite($this->SHPFile, pack('VV', $this->SHPData['numparts'], $this->SHPData['numpoints'])); |
448
|
|
|
|
449
|
6 |
|
$part_index = 0; |
450
|
6 |
|
for ($i = 0; $i < $this->SHPData['numparts']; $i++) { |
451
|
6 |
|
fwrite($this->SHPFile, pack('V', $part_index)); |
452
|
6 |
|
$part_index += count($this->SHPData['parts'][$i]['points']); |
453
|
6 |
|
} |
454
|
|
|
|
455
|
6 |
|
foreach ($this->SHPData['parts'] as $partData) { |
456
|
6 |
|
foreach ($partData['points'] as $pointData) { |
457
|
6 |
|
$this->_savePoint($pointData); |
458
|
6 |
|
} |
459
|
6 |
|
} |
460
|
6 |
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* @param string $type |
464
|
|
|
*/ |
465
|
4 |
|
private function _savePolyLineMZRecord($type) { |
466
|
4 |
|
fwrite($this->SHPFile, pack('dd', $this->SHPData[$type.'min'], $this->SHPData[$type.'max'])); |
467
|
|
|
|
468
|
4 |
|
foreach ($this->SHPData['parts'] as $partData) { |
469
|
4 |
|
foreach ($partData['points'] as $pointData) { |
470
|
4 |
|
fwrite($this->SHPFile, Util::packDouble($pointData[$type])); |
471
|
4 |
|
} |
472
|
4 |
|
} |
473
|
4 |
|
} |
474
|
|
|
|
475
|
2 |
|
private function _savePolyLineMRecord() { |
476
|
2 |
|
$this->_savePolyLineRecord(); |
477
|
|
|
|
478
|
2 |
|
$this->_savePolyLineMZRecord('m'); |
479
|
2 |
|
} |
480
|
|
|
|
481
|
2 |
|
private function _savePolyLineZRecord() { |
482
|
2 |
|
$this->_savePolyLineRecord(); |
483
|
|
|
|
484
|
2 |
|
$this->_savePolyLineMZRecord('z'); |
485
|
2 |
|
$this->_savePolyLineMZRecord('m'); |
486
|
2 |
|
} |
487
|
|
|
|
488
|
3 |
|
private function _loadPolygonRecord() { |
489
|
3 |
|
$this->_loadPolyLineRecord(); |
490
|
3 |
|
} |
491
|
|
|
|
492
|
1 |
|
private function _loadPolygonMRecord() { |
493
|
1 |
|
$this->_loadPolyLineMRecord(); |
494
|
1 |
|
} |
495
|
|
|
|
496
|
2 |
|
private function _loadPolygonZRecord() { |
497
|
2 |
|
$this->_loadPolyLineZRecord(); |
498
|
2 |
|
} |
499
|
|
|
|
500
|
1 |
|
private function _savePolygonRecord() { |
501
|
1 |
|
$this->_savePolyLineRecord(); |
502
|
1 |
|
} |
503
|
|
|
|
504
|
1 |
|
private function _savePolygonMRecord() { |
505
|
1 |
|
$this->_savePolyLineMRecord(); |
506
|
1 |
|
} |
507
|
|
|
|
508
|
1 |
|
private function _savePolygonZRecord() { |
509
|
1 |
|
$this->_savePolyLineZRecord(); |
510
|
1 |
|
} |
511
|
|
|
|
512
|
12 |
|
private function _adjustBBox($point) { |
513
|
|
|
// Adjusts bounding box based on point |
514
|
12 |
|
$directions = array('x', 'y', 'z', 'm'); |
515
|
12 |
|
foreach ($directions as $direction) { |
516
|
12 |
|
if (!isset($point[$direction])) { |
517
|
8 |
|
continue; |
518
|
|
|
} |
519
|
12 |
|
$min = $direction.'min'; |
520
|
12 |
|
$max = $direction.'max'; |
521
|
12 |
|
if (!isset($this->SHPData[$min]) || ($this->SHPData[$min] > $point[$direction])) { |
522
|
12 |
|
$this->SHPData[$min] = $point[$direction]; |
523
|
12 |
|
} |
524
|
12 |
|
if (!isset($this->SHPData[$max]) || ($this->SHPData[$max] < $point[$direction])) { |
525
|
12 |
|
$this->SHPData[$max] = $point[$direction]; |
526
|
12 |
|
} |
527
|
12 |
|
} |
528
|
12 |
|
} |
529
|
|
|
|
530
|
|
|
/** |
531
|
|
|
* Sets dimension to 0 if not set |
532
|
|
|
* |
533
|
|
|
* @param array $point Point to check |
534
|
|
|
* @param string $dimension Dimension to check |
535
|
|
|
* |
536
|
|
|
* @return array |
537
|
|
|
*/ |
538
|
8 |
|
private function _fixPoint($point, $dimension) |
539
|
|
|
{ |
540
|
8 |
|
if (!isset($point[$dimension])) { |
541
|
8 |
|
$point[$dimension] = 0.0; // no_value |
542
|
8 |
|
} |
543
|
8 |
|
return $point; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Adjust point and bounding box when adding point |
548
|
|
|
* |
549
|
|
|
* @param array $point Point data |
550
|
|
|
* |
551
|
|
|
* @return array Fixed point data |
552
|
|
|
*/ |
553
|
12 |
|
private function _adjustPoint($point) |
554
|
|
|
{ |
555
|
12 |
|
$type = $this->shapeType / 10; |
556
|
12 |
|
if ($type >= 2) { |
557
|
4 |
|
$point = $this->_fixPoint($point, 'm'); |
558
|
12 |
|
} elseif ($type >= 1) { |
559
|
4 |
|
$point = $this->_fixPoint($point, 'z'); |
560
|
4 |
|
$point = $this->_fixPoint($point, 'm'); |
561
|
4 |
|
} |
562
|
12 |
|
$this->_adjustBBox($point); |
563
|
12 |
|
} |
564
|
|
|
|
565
|
12 |
|
public function addPoint($point, $partIndex = 0) { |
566
|
12 |
|
$point = $this->_adjustPoint($point); |
567
|
12 |
|
switch ($this->shapeType) { |
568
|
12 |
|
case 0: |
569
|
|
|
//Don't add anything |
570
|
|
|
return; |
571
|
12 |
|
case 1: |
572
|
12 |
|
case 11: |
573
|
12 |
|
case 21: |
574
|
|
|
//Substitutes the value of the current point |
575
|
3 |
|
$this->SHPData = $point; |
|
|
|
|
576
|
3 |
|
break; |
577
|
9 |
|
case 3: |
578
|
9 |
|
case 5: |
579
|
9 |
|
case 13: |
580
|
9 |
|
case 15: |
581
|
9 |
|
case 23: |
582
|
9 |
|
case 25: |
583
|
|
|
//Adds a new point to the selected part |
584
|
6 |
|
$this->SHPData['parts'][$partIndex]['points'][] = $point; |
585
|
6 |
|
$this->SHPData['numparts'] = count($this->SHPData['parts']); |
586
|
6 |
|
$this->SHPData['numpoints'] = 1 + (isset($this->SHPData['numpoints']) ? $this->SHPData['numpoints'] : 0); |
587
|
6 |
|
break; |
588
|
3 |
|
case 8: |
589
|
3 |
|
case 18: |
590
|
3 |
|
case 28: |
591
|
|
|
//Adds a new point |
592
|
3 |
|
$this->SHPData['points'][] = $point; |
593
|
3 |
|
$this->SHPData['numpoints'] = 1 + (isset($this->SHPData['numpoints']) ? $this->SHPData['numpoints'] : 0); |
594
|
3 |
|
break; |
595
|
|
|
default: |
596
|
|
|
$this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)); |
597
|
|
|
return; |
598
|
12 |
|
} |
599
|
12 |
|
} |
600
|
|
|
|
601
|
12 |
|
public function deletePoint($pointIndex = 0, $partIndex = 0) { |
602
|
12 |
|
switch ($this->shapeType) { |
603
|
12 |
|
case 0: |
604
|
|
|
//Don't delete anything |
605
|
|
|
break; |
606
|
12 |
|
case 1: |
607
|
12 |
|
case 11: |
608
|
12 |
|
case 21: |
609
|
|
|
//Sets the value of the point to zero |
610
|
3 |
|
$this->SHPData['x'] = 0.0; |
611
|
3 |
|
$this->SHPData['y'] = 0.0; |
612
|
3 |
|
if (in_array($this->shapeType, array(11, 21))) { |
613
|
2 |
|
$this->SHPData['m'] = 0.0; |
614
|
2 |
|
} |
615
|
3 |
|
if (in_array($this->shapeType, array(11))) { |
616
|
1 |
|
$this->SHPData['z'] = 0.0; |
617
|
1 |
|
} |
618
|
3 |
|
break; |
619
|
9 |
|
case 3: |
620
|
9 |
|
case 5: |
621
|
9 |
|
case 13: |
622
|
9 |
|
case 15: |
623
|
9 |
|
case 23: |
624
|
9 |
|
case 25: |
625
|
|
|
//Deletes the point from the selected part, if exists |
626
|
6 |
|
if (isset($this->SHPData['parts'][$partIndex]) && isset($this->SHPData['parts'][$partIndex]['points'][$pointIndex])) { |
627
|
|
|
$count = count($this->SHPData['parts'][$partIndex]['points']) - 1; |
628
|
|
|
for ($i = $pointIndex; $i < $count; $i++) { |
629
|
|
|
$this->SHPData['parts'][$partIndex]['points'][$i] = $this->SHPData['parts'][$partIndex]['points'][$i + 1]; |
630
|
|
|
} |
631
|
|
|
unset($this->SHPData['parts'][$partIndex]['points'][count($this->SHPData['parts'][$partIndex]['points']) - 1]); |
632
|
|
|
|
633
|
|
|
$this->SHPData['numparts'] = count($this->SHPData['parts']); |
634
|
|
|
$this->SHPData['numpoints']--; |
635
|
|
|
} |
636
|
6 |
|
break; |
637
|
3 |
|
case 8: |
638
|
3 |
|
case 18: |
639
|
3 |
|
case 28: |
640
|
|
|
//Deletes the point, if exists |
641
|
3 |
|
if (isset($this->SHPData['points'][$pointIndex])) { |
642
|
|
|
$count = count($this->SHPData['points']) - 1; |
643
|
|
|
for ($i = $pointIndex; $i < $count; $i++) { |
644
|
|
|
$this->SHPData['points'][$i] = $this->SHPData['points'][$i + 1]; |
645
|
|
|
} |
646
|
|
|
unset($this->SHPData['points'][count($this->SHPData['points']) - 1]); |
647
|
|
|
|
648
|
|
|
$this->SHPData['numpoints']--; |
649
|
|
|
} |
650
|
3 |
|
break; |
651
|
|
|
default: |
652
|
|
|
$this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)); |
653
|
|
|
break; |
654
|
12 |
|
} |
655
|
12 |
|
} |
656
|
|
|
|
657
|
12 |
|
public function getContentLength() { |
658
|
|
|
// The content length for a record is the length of the record contents section measured in 16-bit words. |
659
|
|
|
// one coordinate makes 4 16-bit words (64 bit double) |
660
|
12 |
|
switch ($this->shapeType) { |
661
|
12 |
|
case 0: |
662
|
|
|
$result = 0; |
663
|
|
|
break; |
664
|
12 |
|
case 1: |
665
|
1 |
|
$result = 10; |
666
|
1 |
|
break; |
667
|
11 |
|
case 21: |
668
|
1 |
|
$result = 10 + 4; |
669
|
1 |
|
break; |
670
|
10 |
|
case 11: |
671
|
1 |
|
$result = 10 + 8; |
672
|
1 |
|
break; |
673
|
9 |
|
case 3: |
674
|
9 |
|
case 5: |
675
|
2 |
|
$count = count($this->SHPData['parts']); |
676
|
2 |
|
$result = 22 + 2 * $count; |
677
|
2 |
|
for ($i = 0; $i < $count; $i++) { |
678
|
2 |
|
$result += 8 * count($this->SHPData['parts'][$i]['points']); |
679
|
2 |
|
} |
680
|
2 |
|
break; |
681
|
7 |
|
case 23: |
682
|
7 |
View Code Duplication |
case 25: |
683
|
2 |
|
$count = count($this->SHPData['parts']); |
684
|
2 |
|
$result = 22 + (2 * 4) + 2 * $count; |
685
|
2 |
|
for ($i = 0; $i < $count; $i++) { |
686
|
2 |
|
$result += (8 + 4) * count($this->SHPData['parts'][$i]['points']); |
687
|
2 |
|
} |
688
|
2 |
|
break; |
689
|
5 |
|
case 13: |
690
|
5 |
View Code Duplication |
case 15: |
691
|
2 |
|
$count = count($this->SHPData['parts']); |
692
|
2 |
|
$result = 22 + (4 * 4) + 2 * $count; |
693
|
2 |
|
for ($i = 0; $i < $count; $i++) { |
694
|
2 |
|
$result += (8 + 8) * count($this->SHPData['parts'][$i]['points']); |
695
|
2 |
|
} |
696
|
2 |
|
break; |
697
|
3 |
|
case 8: |
698
|
1 |
|
$result = 20 + 8 * count($this->SHPData['points']); |
699
|
1 |
|
break; |
700
|
2 |
View Code Duplication |
case 28: |
701
|
1 |
|
$result = 20 + (2 * 4) + (8 + 4) * count($this->SHPData['points']); |
702
|
1 |
|
break; |
703
|
1 |
View Code Duplication |
case 18: |
704
|
1 |
|
$result = 20 + (4 * 4) + (8 + 8) * count($this->SHPData['points']); |
705
|
1 |
|
break; |
706
|
|
|
default: |
707
|
|
|
$result = false; |
708
|
|
|
$this->setError(sprintf('The Shape Type "%s" is not supported.', $this->shapeType)); |
709
|
|
|
break; |
710
|
12 |
|
} |
711
|
12 |
|
return $result; |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
private function _loadDBFData() { |
715
|
|
|
$this->DBFData = @dbase_get_record_with_names($this->DBFFile, $this->recordNumber); |
716
|
|
|
unset($this->DBFData['deleted']); |
717
|
|
|
} |
718
|
|
|
|
719
|
|
|
private function _saveDBFData() { |
720
|
|
|
if (count($this->DBFData) == 0) { |
721
|
|
|
return; |
722
|
|
|
} |
723
|
|
|
unset($this->DBFData['deleted']); |
724
|
|
|
if ($this->recordNumber <= dbase_numrecords($this->DBFFile)) { |
725
|
|
|
if (!dbase_replace_record($this->DBFFile, array_values($this->DBFData), $this->recordNumber)) { |
726
|
|
|
$this->setError('I wasn\'t possible to update the information in the DBF file.'); |
727
|
|
|
} |
728
|
|
|
} else { |
729
|
|
|
if (!dbase_add_record($this->DBFFile, array_values($this->DBFData))) { |
730
|
|
|
$this->setError('I wasn\'t possible to add the information to the DBF file.'); |
731
|
|
|
} |
732
|
|
|
} |
733
|
|
|
} |
734
|
|
|
|
735
|
|
|
/** |
736
|
|
|
* Sets error message |
737
|
|
|
* |
738
|
|
|
* @param string $error |
739
|
|
|
* |
740
|
|
|
* @return void |
741
|
|
|
*/ |
742
|
|
|
public function setError($error) { |
743
|
|
|
$this->lastError = $error; |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
/** |
747
|
|
|
* Returns shape name |
748
|
|
|
* |
749
|
|
|
* @return string |
750
|
|
|
*/ |
751
|
1 |
|
public function getShapeName() |
752
|
|
|
{ |
753
|
1 |
|
return Util::nameShape($this->shapeType); |
754
|
|
|
} |
755
|
|
|
} |
756
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.