Project

General

Profile

Download (15.1 KB) Statistics
| Branch: | Tag: | Revision:
1
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2
 * full list of contributors). Published under the 2-clause BSD license.
3
 * See license.txt in the OpenLayers distribution or repository for the
4
 * full text of the license. */
5

    
6
/**
7
 * @requires OpenLayers/Format.js
8
 * @requires OpenLayers/Feature/Vector.js
9
 */
10

    
11
/**
12
 * Class: OpenLayers.Format.EncodedPolyline
13
 * Class for reading and writing encoded polylines.  Create a new instance
14
 * with the <OpenLayers.Format.EncodedPolyline> constructor.
15
 *
16
 * Inherits from:
17
 *  - <OpenLayers.Format>
18
 */
19
OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, {
20

    
21
    /**
22
     * APIProperty: geometryType
23
     * {String} Geometry type to output. One of: linestring (default),
24
     *     linearring, point, multipoint or polygon. If the geometryType is
25
     *     point, only the first point of the string is returned.
26
     */
27
    geometryType: "linestring",
28

    
29
    /**
30
     * Constructor: OpenLayers.Format.EncodedPolyline
31
     * Create a new parser for encoded polylines
32
     *
33
     * Parameters:
34
     * options - {Object} An optional object whose properties will be set on
35
     *           this instance
36
     *
37
     * Returns:
38
     * {<OpenLayers.Format.EncodedPolyline>} A new encoded polylines parser.
39
     */
40
    initialize: function(options) {
41
        OpenLayers.Format.prototype.initialize.apply(this, [options]);
42
    },
43

    
44
    /**
45
     * APIMethod: read
46
     * Deserialize an encoded polyline string and return a vector feature.
47
     *
48
     * Parameters:
49
     * encoded - {String} An encoded polyline string
50
     *
51
     * Returns:
52
     * {<OpenLayers.Feature.Vector>} A vector feature with a linestring.
53
     */
54
    read: function(encoded) {
55
        var geomType;
56
        if (this.geometryType == "linestring")
57
            geomType = OpenLayers.Geometry.LineString;
58
        else if (this.geometryType == "linearring")
59
            geomType = OpenLayers.Geometry.LinearRing;
60
        else if (this.geometryType == "multipoint")
61
            geomType = OpenLayers.Geometry.MultiPoint;
62
        else if (this.geometryType != "point" && this.geometryType != "polygon")
63
            return null;
64

    
65
        var flatPoints = this.decodeDeltas(encoded, 2);
66
        var flatPointsLength = flatPoints.length;
67

    
68
        var pointGeometries = [];
69
        for (var i = 0; i + 1 < flatPointsLength;) {
70
            var y = flatPoints[i++], x = flatPoints[i++];
71
            pointGeometries.push(new OpenLayers.Geometry.Point(x, y));
72
        }
73

    
74

    
75
        if (this.geometryType == "point")
76
            return new OpenLayers.Feature.Vector(
77
                pointGeometries[0]
78
            );
79

    
80
        if (this.geometryType == "polygon")
81
            return new OpenLayers.Feature.Vector(
82
                new OpenLayers.Geometry.Polygon([
83
                    new OpenLayers.Geometry.LinearRing(pointGeometries)
84
                ])
85
            );
86

    
87
        return new OpenLayers.Feature.Vector(
88
            new geomType(pointGeometries)
89
        );
90
    },
91

    
92
    /**
93
     * APIMethod: decode
94
     * Deserialize an encoded string and return an array of n-dimensional
95
     * points.
96
     *
97
     * Parameters:
98
     * encoded - {String} An encoded string
99
     * dims - {int} The dimension of the points that are returned
100
     *
101
     * Returns:
102
     * {Array(Array(int))} An array containing n-dimensional arrays of
103
     *     coordinates.
104
     */
105
    decode: function(encoded, dims, opt_factor) {
106
        var factor = opt_factor || 1e5;
107
        var flatPoints = this.decodeDeltas(encoded, dims, factor);
108
        var flatPointsLength = flatPoints.length;
109

    
110
        var points = [];
111
        for (var i = 0; i + (dims - 1) < flatPointsLength;) {
112
            var point = [];
113

    
114
            for (var dim = 0; dim < dims; ++dim) {
115
                point.push(flatPoints[i++])
116
            }
117

    
118
            points.push(point);
119
        }
120

    
121
        return points;
122
    },
123

    
124
    /**
125
     * APIMethod: write
126
     * Serialize a feature or array of features into a WKT string.
127
     *
128
     * Parameters:
129
     * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
130
     *            features
131
     *
132
     * Returns:
133
     * {String} The WKT string representation of the input geometries
134
     */
135
    write: function(features) {
136
        var feature;
137
        if (features.constructor == Array)
138
            feature = features[0];
139
        else
140
            feature = features;
141

    
142
        var geometry = feature.geometry;
143
        var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
144

    
145
        var pointGeometries;
146
        if (type == "point")
147
            pointGeometries = new Array(geometry);
148
        else if (type == "linestring" ||
149
                 type == "linearring" ||
150
                 type == "multipoint")
151
            pointGeometries = geometry.components;
152
        else if (type == "polygon")
153
            pointGeometries = geometry.components[0].components;
154
        else
155
            return null;
156

    
157
        var flatPoints = [];
158

    
159
        var pointGeometriesLength = pointGeometries.length;
160
        for (var i = 0; i < pointGeometriesLength; ++i) {
161
            var pointGeometry = pointGeometries[i];
162
            flatPoints.push(pointGeometry.y);
163
            flatPoints.push(pointGeometry.x);
164
        }
165

    
166
        return this.encodeDeltas(flatPoints, 2);
167
    },
168

    
169
    /**
170
     * APIMethod: encode
171
     * Serialize an array of n-dimensional points and return an encoded string
172
     *
173
     * Parameters:
174
     * points - {Array(Array(int))} An array containing n-dimensional
175
     *          arrays of coordinates
176
     * dims - {int} The dimension of the points that should be read
177
     *
178
     * Returns:
179
     * {String} An encoded string
180
     */
181
    encode: function (points, dims, opt_factor) {
182
        var factor = opt_factor || 1e5;
183
        var flatPoints = [];
184

    
185
        var pointsLength = points.length;
186
        for (var i = 0; i < pointsLength; ++i) {
187
            var point = points[i];
188

    
189
            for (var dim = 0; dim < dims; ++dim) {
190
                flatPoints.push(point[dim]);
191
            }
192
        }
193

    
194
        return this.encodeDeltas(flatPoints, dims, factor);
195
    },
196

    
197
    /**
198
     * APIMethod: encodeDeltas
199
     * Encode a list of n-dimensional points and return an encoded string
200
     *
201
     * Attention: This function will modify the passed array!
202
     *
203
     * Parameters:
204
     * numbers - {Array.<number>} A list of n-dimensional points.
205
     * dimension - {number} The dimension of the points in the list.
206
     * opt_factor - {number=} The factor by which the numbers will be
207
     * multiplied. The remaining decimal places will get rounded away.
208
     *
209
     * Returns:
210
     * {string} The encoded string.
211
     */
212
    encodeDeltas: function(numbers, dimension, opt_factor) {
213
      var factor = opt_factor || 1e5;
214
      var d;
215

    
216
      var lastNumbers = new Array(dimension);
217
      for (d = 0; d < dimension; ++d) {
218
        lastNumbers[d] = 0;
219
      }
220

    
221
      var numbersLength = numbers.length;
222
      for (var i = 0; i < numbersLength;) {
223
        for (d = 0; d < dimension; ++d, ++i) {
224
          var num = numbers[i];
225
          var delta = num - lastNumbers[d];
226
          lastNumbers[d] = num;
227

    
228
          numbers[i] = delta;
229
        }
230
      }
231

    
232
      return this.encodeFloats(numbers, factor);
233
    },
234

    
235

    
236
    /**
237
     * APIMethod: decodeDeltas
238
     * Decode a list of n-dimensional points from an encoded string
239
     *
240
     * Parameters:
241
     * encoded - {string} An encoded string.
242
     * dimension - {number} The dimension of the points in the encoded string.
243
     * opt_factor - {number=} The factor by which the resulting numbers will
244
     * be divided.
245
     *
246
     * Returns:
247
     * {Array.<number>} A list of n-dimensional points.
248
     */
249
    decodeDeltas: function(encoded, dimension, opt_factor) {
250
      var factor = opt_factor || 1e5;
251
      var d;
252

    
253
      var lastNumbers = new Array(dimension);
254
      for (d = 0; d < dimension; ++d) {
255
        lastNumbers[d] = 0;
256
      }
257

    
258
      var numbers = this.decodeFloats(encoded, factor);
259

    
260
      var numbersLength = numbers.length;
261
      for (var i = 0; i < numbersLength;) {
262
        for (d = 0; d < dimension; ++d, ++i) {
263
          lastNumbers[d] += numbers[i];
264

    
265
          numbers[i] = lastNumbers[d];
266
        }
267
      }
268

    
269
      return numbers;
270
    },
271

    
272

    
273
    /**
274
     * APIMethod: encodeFloats
275
     * Encode a list of floating point numbers and return an encoded string
276
     *
277
     * Attention: This function will modify the passed array!
278
     *
279
     * Parameters:
280
     * numbers - {Array.<number>} A list of floating point numbers.
281
     * opt_factor - {number=} The factor by which the numbers will be
282
     * multiplied. The remaining decimal places will get rounded away.
283
     *
284
     * Returns:
285
     * {string} The encoded string.
286
     */
287
    encodeFloats: function(numbers, opt_factor) {
288
      var factor = opt_factor || 1e5;
289

    
290
      var numbersLength = numbers.length;
291
      for (var i = 0; i < numbersLength; ++i) {
292
        numbers[i] = Math.round(numbers[i] * factor);
293
      }
294

    
295
      return this.encodeSignedIntegers(numbers);
296
    },
297

    
298

    
299
    /**
300
     * APIMethod: decodeFloats
301
     * Decode a list of floating point numbers from an encoded string
302
     *
303
     * Parameters:
304
     * encoded - {string} An encoded string.
305
     * opt_factor - {number=} The factor by which the result will be divided.
306
     *
307
     * Returns:
308
     * {Array.<number>} A list of floating point numbers.
309
     */
310
    decodeFloats: function(encoded, opt_factor) {
311
      var factor = opt_factor || 1e5;
312

    
313
      var numbers = this.decodeSignedIntegers(encoded);
314

    
315
      var numbersLength = numbers.length;
316
      for (var i = 0; i < numbersLength; ++i) {
317
        numbers[i] /= factor;
318
      }
319

    
320
      return numbers;
321
    },
322

    
323

    
324
    /**
325
     * APIMethod: encodeSignedIntegers
326
     * Encode a list of signed integers and return an encoded string
327
     *
328
     * Attention: This function will modify the passed array!
329
     *
330
     * Parameters:
331
     * numbers - {Array.<number>} A list of signed integers.
332
     *
333
     * Returns:
334
     * {string} The encoded string.
335
     */
336
    encodeSignedIntegers: function(numbers) {
337
      var numbersLength = numbers.length;
338
      for (var i = 0; i < numbersLength; ++i) {
339
        var num = numbers[i];
340

    
341
        var signedNum = num << 1;
342
        if (num < 0) {
343
          signedNum = ~(signedNum);
344
        }
345

    
346
        numbers[i] = signedNum;
347
      }
348

    
349
      return this.encodeUnsignedIntegers(numbers);
350
    },
351

    
352

    
353
    /**
354
     * APIMethod: decodeSignedIntegers
355
     * Decode a list of signed integers from an encoded string
356
     *
357
     * Parameters:
358
     * encoded - {string} An encoded string.
359
     *
360
     * Returns:
361
     * {Array.<number>} A list of signed integers.
362
     */
363
    decodeSignedIntegers: function(encoded) {
364
      var numbers = this.decodeUnsignedIntegers(encoded);
365

    
366
      var numbersLength = numbers.length;
367
      for (var i = 0; i < numbersLength; ++i) {
368
        var num = numbers[i];
369
        numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
370
      }
371

    
372
      return numbers;
373
    },
374

    
375

    
376
    /**
377
     * APIMethod: encodeUnsignedIntegers
378
     * Encode a list of unsigned integers and return an encoded string
379
     *
380
     * Parameters:
381
     * numbers - {Array.<number>} A list of unsigned integers.
382
     *
383
     * Returns:
384
     * {string} The encoded string.
385
     */
386
    encodeUnsignedIntegers: function(numbers) {
387
      var encoded = '';
388

    
389
      var numbersLength = numbers.length;
390
      for (var i = 0; i < numbersLength; ++i) {
391
        encoded += this.encodeUnsignedInteger(numbers[i]);
392
      }
393

    
394
      return encoded;
395
    },
396

    
397

    
398
    /**
399
     * APIMethod: decodeUnsignedIntegers
400
     * Decode a list of unsigned integers from an encoded string
401
     *
402
     * Parameters:
403
     * encoded - {string} An encoded string.
404
     *
405
     * Returns:
406
     * {Array.<number>} A list of unsigned integers.
407
     */
408
    decodeUnsignedIntegers: function(encoded) {
409
      var numbers = [];
410

    
411
      var current = 0;
412
      var shift = 0;
413

    
414
      var encodedLength = encoded.length;
415
      for (var i = 0; i < encodedLength; ++i) {
416
        var b = encoded.charCodeAt(i) - 63;
417

    
418
        current |= (b & 0x1f) << shift;
419

    
420
        if (b < 0x20) {
421
          numbers.push(current);
422
          current = 0;
423
          shift = 0;
424
        } else {
425
          shift += 5;
426
        }
427
      }
428

    
429
      return numbers;
430
    },
431

    
432

    
433
    /**
434
     * Method: encodeFloat
435
     * Encode one single floating point number and return an encoded string
436
     *
437
     * Parameters:
438
     * num - {number} Floating point number that should be encoded.
439
     * opt_factor - {number=} The factor by which num will be multiplied.
440
     * The remaining decimal places will get rounded away.
441
     *
442
     * Returns:
443
     * {string} The encoded string.
444
     */
445
    encodeFloat: function(num, opt_factor) {
446
      num = Math.round(num * (opt_factor || 1e5));
447
      return this.encodeSignedInteger(num);
448
    },
449

    
450

    
451
    /**
452
     * Method: decodeFloat
453
     * Decode one single floating point number from an encoded string
454
     *
455
     * Parameters:
456
     * encoded - {string} An encoded string.
457
     * opt_factor - {number=} The factor by which the result will be divided.
458
     *
459
     * Returns:
460
     * {number} The decoded floating point number.
461
     */
462
    decodeFloat: function(encoded, opt_factor) {
463
      var result = this.decodeSignedInteger(encoded);
464
      return result / (opt_factor || 1e5);
465
    },
466

    
467

    
468
    /**
469
     * Method: encodeSignedInteger
470
     * Encode one single signed integer and return an encoded string
471
     *
472
     * Parameters:
473
     * num - {number} Signed integer that should be encoded.
474
     *
475
     * Returns:
476
     * {string} The encoded string.
477
     */
478
    encodeSignedInteger: function(num) {
479
      var signedNum = num << 1;
480
      if (num < 0) {
481
        signedNum = ~(signedNum);
482
      }
483

    
484
      return this.encodeUnsignedInteger(signedNum);
485
    },
486

    
487

    
488
    /**
489
     * Method: decodeSignedInteger
490
     * Decode one single signed integer from an encoded string
491
     *
492
     * Parameters:
493
     * encoded - {string} An encoded string.
494
     *
495
     * Returns:
496
     * {number} The decoded signed integer.
497
     */
498
    decodeSignedInteger: function(encoded) {
499
      var result = this.decodeUnsignedInteger(encoded);
500
      return ((result & 1) ? ~(result >> 1) : (result >> 1));
501
    },
502

    
503

    
504
    /**
505
     * Method: encodeUnsignedInteger
506
     * Encode one single unsigned integer and return an encoded string
507
     *
508
     * Parameters:
509
     * num - {number} Unsigned integer that should be encoded.
510
     *
511
     * Returns:
512
     * {string} The encoded string.
513
     */
514
    encodeUnsignedInteger: function(num) {
515
      var value, encoded = '';
516
      while (num >= 0x20) {
517
        value = (0x20 | (num & 0x1f)) + 63;
518
        encoded += (String.fromCharCode(value));
519
        num >>= 5;
520
      }
521
      value = num + 63;
522
      encoded += (String.fromCharCode(value));
523
      return encoded;
524
    },
525

    
526

    
527
    /**
528
     * Method: decodeUnsignedInteger
529
     * Decode one single unsigned integer from an encoded string
530
     *
531
     * Parameters:
532
     * encoded - {string} An encoded string.
533
     *
534
     * Returns:
535
     * {number} The decoded unsigned integer.
536
     */
537
    decodeUnsignedInteger: function(encoded) {
538
      var result = 0;
539
      var shift = 0;
540

    
541
      var encodedLength = encoded.length;
542
      for (var i = 0; i < encodedLength; ++i) {
543
        var b = encoded.charCodeAt(i) - 63;
544

    
545
        result |= (b & 0x1f) << shift;
546

    
547
        if (b < 0x20)
548
          break;
549

    
550
        shift += 5;
551
      }
552

    
553
      return result;
554
    },
555

    
556
    CLASS_NAME: "OpenLayers.Format.EncodedPolyline"
557
});
(7-7/41)