Passed
Push — master ( 58539d...96b0d3 )
by Mark
01:31
created

WKB::getGeometry()   C

Complexity

Conditions 12
Paths 65

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 35
rs 6.9666
c 0
b 0
f 0
cc 12
nc 65
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * (c) Patrick Hayes
4
 *
5
 * This code is open-source and licenced under the Modified BSD License.
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
/**
11
 * PHP Geometry/WKB encoder/decoder
12
 *
13
 */
14
class WKB extends GeoAdapter
15
{
16
17
  private $dimension = 2;
18
  private $z = FALSE;
19
  private $m = FALSE;
20
21
  /**
22
   * Read WKB into geometry objects
23
   *
24
   * @param string $wkb
25
   *   Well-known-binary string
26
   * @param bool $is_hex_string
27
   *   If this is a hexedecimal string that is in need of packing
28
   *
29
   * @return Geometry
30
   */
31
  public function read($wkb, $is_hex_string = FALSE) {
32
    if ($is_hex_string) {
33
      $wkb = pack('H*',$wkb);
34
    }
35
36
    if (empty($wkb)) {
37
      throw new Exception('Cannot read empty WKB geometry. Found ' . gettype($wkb));
38
    }
39
40
    $mem = fopen('php://memory', 'r+');
41
    fwrite($mem, $wkb);
42
    fseek($mem, 0);
43
44
    $geometry = $this->getGeometry($mem);
45
    fclose($mem);
46
    return $geometry;
47
  }
48
49
  function getGeometry(&$mem) {
50
    $base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
51
    if ($base_info['order'] !== 1) {
52
      throw new Exception('Only NDR (little endian) SKB format is supported at the moment');
53
    }
54
55
    if ($base_info['z']) {
56
      $this->dimension++;
57
      $this->z = TRUE;
58
    }
59
    if ($base_info['m']) {
60
      $this->dimension++;
61
      $this->m = TRUE;
62
    }
63
64
    // If there is SRID information, ignore it - use EWKB Adapter to get SRID support
65
    if ($base_info['s']) {
66
      fread($mem, 4);
67
    }
68
69
    switch ($base_info['type']) {
70
      case 1:
71
        return $this->getPoint($mem);
72
      case 2:
73
        return $this->getLinstring($mem);
74
      case 3:
75
        return $this->getPolygon($mem);
76
      case 4:
77
        return $this->getMulti($mem,'point');
78
      case 5:
79
        return $this->getMulti($mem,'line');
80
      case 6:
81
        return $this->getMulti($mem,'polygon');
82
      case 7:
83
        return $this->getMulti($mem,'geometry');
84
    }
85
  }
86
87
  function getPoint(&$mem) {
88
    $point_coords = unpack("d*", fread($mem,$this->dimension*8));
89
    if (!empty($point_coords)) {
90
      return new Point($point_coords[1],$point_coords[2]);
91
    }
92
    else {
93
      return new Point(); // EMPTY point
94
    }
95
  }
96
97
  function getLinstring(&$mem) {
98
    // Get the number of points expected in this string out of the first 4 bytes
99
    $line_length = unpack('L',fread($mem,4));
100
101
    // Return an empty linestring if there is no line-length
102
    if (!$line_length[1]) return new LineString();
103
104
    // Read the nubmer of points x2 (each point is two coords) into decimal-floats
105
    $line_coords = unpack('d*', fread($mem,$line_length[1]*$this->dimension*8));
106
107
    // We have our coords, build up the linestring
108
    $components = array();
109
    $i = 1;
110
    $num_coords = count($line_coords);
111
    while ($i <= $num_coords) {
112
      $components[] = new Point($line_coords[$i],$line_coords[$i+1]);
113
      $i += 2;
114
    }
115
    return new LineString($components);
116
  }
117
118
  function getPolygon(&$mem) {
119
    // Get the number of linestring expected in this poly out of the first 4 bytes
120
    $poly_length = unpack('L',fread($mem,4));
121
122
    $components = array();
123
    $i = 1;
124
    while ($i <= $poly_length[1]) {
125
      $components[] = $this->getLinstring($mem);
126
      $i++;
127
    }
128
    return new Polygon($components);
129
  }
130
131
  function getMulti(&$mem, $type) {
132
    // Get the number of items expected in this multi out of the first 4 bytes
133
    $multi_length = unpack('L',fread($mem,4));
134
135
    $components = array();
136
    $i = 1;
137
    while ($i <= $multi_length[1]) {
138
      $components[] = $this->getGeometry($mem);
139
      $i++;
140
    }
141
    switch ($type) {
142
      case 'point':
143
        return new MultiPoint($components);
144
      case 'line':
145
        return new MultiLineString($components);
146
      case 'polygon':
147
        return new MultiPolygon($components);
148
      case 'geometry':
149
        return new GeometryCollection($components);
150
    }
151
  }
152
153
  /**
154
   * Serialize geometries into WKB string.
155
   *
156
   * @param Geometry $geometry
157
   *
158
   * @return string The WKB string representation of the input geometries
159
   */
160
  public function write(Geometry $geometry, $write_as_hex = FALSE) {
161
    // We always write into NDR (little endian)
162
    $wkb = pack('c',1);
163
164
    switch ($geometry->getGeomType()) {
165
      case 'Point';
166
        $wkb .= pack('L',1);
167
        $wkb .= $this->writePoint($geometry);
168
        break;
169
      case 'LineString';
170
        $wkb .= pack('L',2);
171
        $wkb .= $this->writeLineString($geometry);
172
        break;
173
      case 'Polygon';
174
        $wkb .= pack('L',3);
175
        $wkb .= $this->writePolygon($geometry);
176
        break;
177
      case 'MultiPoint';
178
        $wkb .= pack('L',4);
179
        $wkb .= $this->writeMulti($geometry);
180
        break;
181
      case 'MultiLineString';
182
        $wkb .= pack('L',5);
183
        $wkb .= $this->writeMulti($geometry);
184
        break;
185
      case 'MultiPolygon';
186
        $wkb .= pack('L',6);
187
        $wkb .= $this->writeMulti($geometry);
188
        break;
189
      case 'GeometryCollection';
190
        $wkb .= pack('L',7);
191
        $wkb .= $this->writeMulti($geometry);
192
        break;
193
    }
194
195
    if ($write_as_hex) {
196
      $unpacked = unpack('H*',$wkb);
197
      return $unpacked[1];
198
    }
199
    else {
200
      return $wkb;
201
    }
202
  }
203
204
  function writePoint($point) {
205
    // Set the coords
206
    if (!$point->isEmpty()) {
207
      $wkb = pack('dd',$point->x(), $point->y());
208
      return $wkb;
209
    } else {
210
      return '';
211
    }
212
  }
213
214
  function writeLineString($line) {
215
    // Set the number of points in this line
216
    $wkb = pack('L',$line->numPoints());
217
218
    // Set the coords
219
    foreach ($line->getComponents() as $point) {
220
      $wkb .= pack('dd',$point->x(), $point->y());
221
    }
222
223
    return $wkb;
224
  }
225
226
  function writePolygon($poly) {
227
    // Set the number of lines in this poly
228
    $wkb = pack('L',$poly->numGeometries());
229
230
    // Write the lines
231
    foreach ($poly->getComponents() as $line) {
232
      $wkb .= $this->writeLineString($line);
233
    }
234
235
    return $wkb;
236
  }
237
238
  function writeMulti($geometry) {
239
    // Set the number of components
240
    $wkb = pack('L',$geometry->numGeometries());
241
242
    // Write the components
243
    foreach ($geometry->getComponents() as $component) {
244
      $wkb .= $this->write($component);
245
    }
246
247
    return $wkb;
248
  }
249
250
}
251